代码之家  ›  专栏  ›  技术社区  ›  Garry Shutler

在.NET中将对象序列化为UTF-8XML

  •  97
  • Garry Shutler  · 技术社区  · 15 年前

    为了简洁起见,删除了适当的对象处理,但如果这是在内存中将对象编码为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();
    
    4 回复  |  直到 15 年前
        1
  •  55
  •   Jon Hanna    15 年前

    当您再次将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流、数据库等。总之,它并没有那么冗长。

        2
  •  296
  •   Jon Skeet    10 年前

    StringWriter MemoryStream . 但是,要将其强制转换为XML,需要使用 字符串编写器 它覆盖了 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是到目前为止最常用的“自定义”编码 :)

    现在正如乔恩·汉纳所说,这仍然是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”的声明编码,我相信这是我们想要的。

        3
  •  17
  •   Sebastian Castaldi    13 年前

    public class Utf8StringWriter : StringWriter
    {
        public Utf8StringWriter(StringBuilder sb) : base (sb)
        {
        }
        public override Encoding Encoding { get { return Encoding.UTF8; } }
    }
    
        4
  •  5
  •   Eric J.    7 年前

    我发现这篇博文很好地解释了这个问题,并定义了一些不同的解决方案:

    (死链接已删除)

    我认为最好的方法是在内存中完全省略XML声明。实际上是这样的

    正如@Jon Hanna提到的,这可以通过如下创建的XmlWriter来完成:

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