간결성을 위해 적절한 개체 처리가 제거되었지만 이것이 메모리에서 개체를 UTF-8로 인코딩하는 가장 간단한 방법이라면 충격을 받았습니다. 더 쉬운 방법이 있어야하지 않나요?
var serializer = new XmlSerializer(typeof(SomeSerializableObject));
var memoryStream = new MemoryStream();
var streamWriter = new StreamWriter(memoryStream, System.Text.Encoding.UTF8);
serializer.Serialize(streamWriter, entry);
memoryStream.Seek(0, SeekOrigin.Begin);
var streamReader = new StreamReader(memoryStream, System.Text.Encoding.UTF8);
var utf8EncodedXml = streamReader.ReadToEnd();
답변
코드는 UTF-8을 다시 문자열로 읽을 때 메모리로 가져 오지 못하므로 더 이상 UTF-8이 아니라 UTF-16으로 다시 돌아갑니다 (이상적으로는 문자열을 다음보다 높은 수준에서 고려하는 것이 가장 좋습니다. 강제하는 경우를 제외하고 모든 인코딩).
실제 UTF-8 옥텟을 얻으려면 다음을 사용할 수 있습니다.
var serializer = new XmlSerializer(typeof(SomeSerializableObject));
var memoryStream = new MemoryStream();
var streamWriter = new StreamWriter(memoryStream, System.Text.Encoding.UTF8);
serializer.Serialize(streamWriter, entry);
byte[] utf8EncodedXml = memoryStream.ToArray();
나는 당신이 남긴 것과 같은 처분을 생략했습니다. 나는 다음을 약간 선호한다 (일반적인 폐기를 남겨둔 상태에서) :
var serializer = new XmlSerializer(typeof(SomeSerializableObject));
using(var memStm = new MemoryStream())
using(var xw = XmlWriter.Create(memStm))
{
serializer.Serialize(xw, entry);
var utf8 = memStm.ToArray();
}
이는 거의 동일한 복잡성이지만 모든 단계에서 다른 작업을 수행 할 합리적인 선택이 있음을 보여줍니다. 가장 시급한 것은 파일, TCP / IP와 같은 메모리가 아닌 다른 곳으로 직렬화하는 것입니다. 스트림, 데이터베이스 등. 대체로 그렇게 장황하지 않습니다.
답변
아니요, a StringWriter
를 사용 하여 중간 MemoryStream
. 그러나 XML로 강제 StringWriter
하려면 Encoding
속성 을 재정의하는를 사용해야 합니다.
public class Utf8StringWriter : StringWriter
{
public override Encoding Encoding => Encoding.UTF8;
}
또는 아직 C # 6을 사용하지 않는 경우 :
public class Utf8StringWriter : StringWriter
{
public override Encoding Encoding { get { return Encoding.UTF8; } }
}
그때:
var serializer = new XmlSerializer(typeof(SomeSerializableObject));
string utf8;
using (StringWriter writer = new Utf8StringWriter())
{
serializer.Serialize(writer, entry);
utf8 = writer.ToString();
}
분명히 Utf8StringWriter
생성자에서 모든 인코딩을 허용하는보다 일반적인 클래스로 만들 수 있습니다. 하지만 내 경험상 UTF-8은 지금까지 가장 일반적으로 필요한 “사용자 지정”인코딩입니다. StringWriter
🙂
이제 Jon Hanna가 말했듯이 이것은 내부적으로 여전히 UTF-16이지만, 아마도 당신은 그것을 이진 데이터로 변환하기 위해 어떤 시점에서 다른 것에 전달할 것입니다 … 그 시점에서 위의 문자열을 사용할 수 있습니다. 이를 UTF-8 바이트로 변환하면 XML 선언이 인코딩으로 “utf-8″을 지정하기 때문에 모두 잘 될 것입니다.
편집 :이 작동을 보여주는 짧지 만 완전한 예 :
using System;
using System.Text;
using System.IO;
using System.Xml.Serialization;
public class Test
{
public int X { get; set; }
static void Main()
{
Test t = new Test();
var serializer = new XmlSerializer(typeof(Test));
string utf8;
using (StringWriter writer = new Utf8StringWriter())
{
serializer.Serialize(writer, t);
utf8 = writer.ToString();
}
Console.WriteLine(utf8);
}
public class Utf8StringWriter : StringWriter
{
public override Encoding Encoding => Encoding.UTF8;
}
}
결과:
<?xml version="1.0" encoding="utf-8"?>
<Test xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<X>0</X>
</Test>
우리가 원했던 “utf-8″의 선언 된 인코딩에 주목하십시오.
답변
상속을 사용하는 아주 좋은 대답입니다. 이니셜 라이저를 재정의하는 것을 잊지 마십시오.
public class Utf8StringWriter : StringWriter
{
public Utf8StringWriter(StringBuilder sb) : base (sb)
{
}
public override Encoding Encoding { get { return Encoding.UTF8; } }
}
답변
문제를 매우 잘 설명하고 몇 가지 다른 솔루션을 정의하는이 블로그 게시물을 찾았습니다.
(데드 링크 제거됨)
이를 수행하는 가장 좋은 방법은 메모리에있을 때 XML 선언을 완전히 생략하는 것이라고 생각했습니다. 어쨌든 실제로 는 그 시점에서 UTF-16이지만 XML 선언은 특정 인코딩을 사용하여 파일에 기록 될 때까지 의미가 없어 보입니다. 그리고 선언도 필요하지 않습니다. 적어도 deserialization을 깨뜨리지 않는 것 같습니다.
@Jon Hanna가 언급했듯이 다음과 같이 만든 XmlWriter로이 작업을 수행 할 수 있습니다.
XmlWriter writer = XmlWriter.Create (output, new XmlWriterSettings() { OmitXmlDeclaration = true });