Programing

.NET에서 객체를 UTF-8 XML로 직렬화

lottogame 2020. 8. 15. 09:43
반응형

.NET에서 객체를 UTF-8 XML로 직렬화


간결성을 위해 적절한 개체 처리가 제거되었지만 이것이 메모리에서 개체를 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은 a에 대해 가장 일반적으로 필요한 "사용자 지정"인코딩입니다. StringWriter:)

Now as Jon Hanna says, this will still be UTF-16 internally, but presumably you're going to pass it to something else at some point, to convert it into binary data... at that point you can use the above string, convert it into UTF-8 bytes, and all will be well - because the XML declaration will specify "utf-8" as the encoding.

EDIT: A short but complete example to show this working:

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;
    }
}

Result:

<?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>

Note the declared encoding of "utf-8" which is what we wanted, I believe.


Very good answer using inheritance, just remember to override the initializer

public class Utf8StringWriter : StringWriter
{
    public Utf8StringWriter(StringBuilder sb) : base (sb)
    {
    }
    public override Encoding Encoding { get { return Encoding.UTF8; } }
}

I found this blog post which explains the problem very well, and defines a few different solutions:

(dead link removed)

I've settled for the idea that the best way to do it is to completely omit the XML declaration when in memory. It actually is UTF-16 at that point anyway, but the XML declaration doesn't seem meaningful until it has been written to a file with a particular encoding; and even then the declaration is not required. It doesn't seem to break deserialization, at least.

As @Jon Hanna mentions, this can be done with an XmlWriter created like this:

XmlWriter writer = XmlWriter.Create (output, new XmlWriterSettings() { OmitXmlDeclaration = true });

참고URL : https://stackoverflow.com/questions/3862063/serializing-an-object-as-utf-8-xml-in-net

반응형