Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在.NET中将对象序列化为UTF-8XML_C#_Xml_Utf 8_Xml Serialization - Fatal编程技术网

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

C# 在.NET中将对象序列化为UTF-8XML,c#,xml,utf-8,xml-serialization,C#,Xml,Utf 8,Xml Serialization,为了简洁起见,删除了适当的对象处理,但如果这是在内存中将对象编码为UTF-8的最简单方法,我会感到震惊。一定有更简单的方法,不是吗 var serializer = new XmlSerializer(typeof(SomeSerializableObject)); var memoryStream = new MemoryStream(); var streamWriter = new StreamWriter(memoryStream, System.Text.Encoding.UTF8)

为了简洁起见,删除了适当的对象处理,但如果这是在内存中将对象编码为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();

不,您可以使用
StringWriter
来摆脱中间
MemoryStream
。但是,要将其强制转换为XML,您需要使用覆盖
编码属性的
StringWriter

public class Utf8StringWriter : StringWriter
{
    public override Encoding Encoding => Encoding.UTF8;
}
或者如果您还没有使用C#6:

然后:

显然,您可以将
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>

0

注意“UTF-8”的声明编码,这是我们想要的,我相信。

< P>你的代码在读回一个字符串时不会将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();
我漏掉了和你一样的处理方法。我略为赞成以下(保留正常处置):


这与复杂性大致相同,但确实表明,在每个阶段都有一个合理的选择来做其他事情,其中最紧迫的是序列化到内存以外的其他地方,例如文件、TCP/IP流、数据库等。总之,其实没有那么详细。

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

(已拆下固定连杆)

我已经接受了这样的想法,即最好的方法是在内存中完全省略XML声明。无论如何,在这一点上它实际上是UTF-16,但是XML声明在使用特定编码写入文件之前似乎没有意义;即使这样,也不需要申报。至少,它似乎没有破坏反序列化

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

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

很好的答案是使用继承,只需记住重写初始值设定项

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

可能是重复的我很困惑…默认编码不是UTF-8吗?@flq,是的,默认编码是UTF-8,虽然这并不重要,因为他再次将其读回字符串,所以
utf8EncodedXml
是UTF-16。@Garry,你能澄清一下吗,因为Jon Skeet和我回答的问题不同。您希望对象序列化为UTF-8,还是希望XML字符串将自身声明为UTF-8,从而在以后用UTF-8编码时具有正确的声明?(在这种情况下,最简单的方法是没有声明,因为这对UTF-8和UTF-16都有效)。@Jon回过头来看,我的问题有歧义。我让它输出到一个字符串,主要是为了调试。实际上,我可能会将字节流传输到磁盘或通过HTTP,这使您的答案与我的问题更直接相关。我遇到的主要问题是XML中UTF-8的声明,但更准确地说,我应该避免字符串的中介,以便实际发送/持久化UTF-8字节,而不是依赖于平台(我认为)的编码。即使覆盖StringWriter上的编码参数,它仍然会将写入的数据发送到StringBuilder,所以还是UTF-16。而且字符串只能是UTF-16。@Jon:你试过了吗?我有,而且很有效。这里重要的是声明的编码;显然,字符串在内部仍然是UTF-16,但在转换为二进制(可以使用任何编码,包括UTF-8)之前,这并没有任何区别。XML序列化程序使用
TextWriter.Encoding
属性来确定要在文档本身中指定的编码名称。@Jon:声明的编码是什么?根据我的经验,这就是像这样的问题真正想要做的——创建一个声明自己是UTF-8格式的XML文档。正如你所说,最好不要认为文本是在任何编码,直到你需要…但是,当XML文档声明一个编码时,这是你需要考虑的问题。“Garry,我现在可以想到的最简单的方法是在我的答案中取第二个例子,但是当你创建<代码> XmlWriter < /代码>时,用一个使用<代码> XmlWriterSettings < /Cord>对象的工厂方法,并将
ommitXMLDeclaration
属性设置为
true
+1您的
Utf8StringWriter
解决方案也非常好和干净。如果您想要抑制BOM,您可以使用
XmlWriter.Create(memoryStream,new XmlWriterSettings{Encoding=new UTF8Encoding(false)})
。如果有人(像我一样)需要读取像Jon所示那样创建的XML,请记住将内存流重新定位为0,否则您将得到一个异常消息“根元素丢失”。这样做:memStm.Position=0;XmlReader=XmlReader.Create(memStm)
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();
}
XmlWriter writer = XmlWriter.Create (output, new XmlWriterSettings() { OmitXmlDeclaration = true });
public class Utf8StringWriter : StringWriter
{
    public Utf8StringWriter(StringBuilder sb) : base (sb)
    {
    }
    public override Encoding Encoding { get { return Encoding.UTF8; } }
}