Почему XmlWriter всегда выводит кодировку utf-16? - PullRequest
26 голосов
/ 27 февраля 2012

У меня есть этот метод расширения

    public static string SerializeObject<T>(this T value)
    {
        var serializer = new XmlSerializer(typeof(T));           
        var settings = new XmlWriterSettings
                       {
                        Encoding = new UTF8Encoding(true), 
                        Indent = false, 
                        OmitXmlDeclaration = false,
                        NewLineHandling = NewLineHandling.None
                       };

        using(var stringWriter = new StringWriter()) 
        {
            using(var xmlWriter = XmlWriter.Create(stringWriter, settings)) 
            {
                serializer.Serialize(xmlWriter, value);
            }

            return stringWriter.ToString();
        }
    }

но всякий раз, когда я вызываю это, указывается кодировка utf-16, то есть <?xml version="1.0" encoding="utf-16"?>. Что я делаю не так?

Ответы [ 6 ]

16 голосов
/ 27 февраля 2012

Строки имеют UTF-16, поэтому при записи в StringWriter всегда будет использоваться UTF-16. Если это не то, что вам нужно, используйте другой производный класс TextWriter с нужной вам кодировкой.

15 голосов
/ 27 февраля 2012

Насколько я знаю, класс StringWriter всегда будет использовать кодировку UTF 16 при сериализации в строку. Вы можете написать свой собственный класс переопределения, который принимает другую кодировку:

public class StringWriterWithEncoding : StringWriter
{
    private readonly Encoding _encoding;

    public StringWriterWithEncoding()
    {
    }

    public StringWriterWithEncoding(IFormatProvider formatProvider)
        : base(formatProvider)
    {
    }

    public StringWriterWithEncoding(StringBuilder sb)
        : base(sb)
    {
    }

    public StringWriterWithEncoding(StringBuilder sb, IFormatProvider formatProvider)
        : base(sb, formatProvider)
    {
    }


    public StringWriterWithEncoding(Encoding encoding)
    {
        _encoding = encoding;
    }

    public StringWriterWithEncoding(IFormatProvider formatProvider, Encoding encoding)
        : base(formatProvider)
    {
        _encoding = encoding;
    }

    public StringWriterWithEncoding(StringBuilder sb, Encoding encoding)
        : base(sb)
    {
        _encoding = encoding;
    }

    public StringWriterWithEncoding(StringBuilder sb, IFormatProvider formatProvider, Encoding encoding)
        : base(sb, formatProvider)
    {
        _encoding = encoding;
    }

    public override Encoding Encoding
    {
        get { return (null == _encoding) ? base.Encoding : _encoding; }
    }
}

Так что вы можете использовать это вместо:

using(var stringWriter = new StringWriterWithEncoding( Encoding.UTF8))
{
   ...
}
1 голос
/ 15 мая 2019

как @ john-saunders упомянул в своем ответе:

StringWriter всегда будет использовать UTF-16

Поэтому я использовал MemoryStream для этих целей.

В моем случае я использую кодировку windows-1251.

var xmlSstring = "";
using (var ms = new MemoryStream())
{
    var encoding = Encoding.GetEncoding(1251);
    var settings = new XmlWriterSettings
    {
        Indent = true,
        Encoding = encoding
    };

    using (var xmlTextWriter = XmlWriter.Create(ms, settings))
    {
        doc.Save(xmlTextWriter);
        xmlString = encoding.GetString(ms.ToArray());
    }
}
1 голос
/ 27 февраля 2012

Вы должны получить новый класс из StringWriter, который имеет свойство переопределенной кодировки.

0 голосов
/ 20 ноября 2018

Если вы не хотите использовать класс, производный от StringWriter, то в вашем случае вы можете просто установить OmitXmlDeclaration на false и объявить свой собственный, как я делаю ниже:

 public static string Serialize<T>(this T value, string xmlDeclaration = "<?xml version=\"1.0\"?>") where T : class, new()
        {
            if (value == null) return string.Empty;

            using (var stringWriter = new StringWriter())
            {
                var settings = new XmlWriterSettings
                {
                    Indent = true,
                    OmitXmlDeclaration = xmlDeclaration != null,
                };

                using (var xmlWriter = XmlWriter.Create(stringWriter, settings))
                {
                    var xmlSerializer = new XmlSerializer(typeof(T));

                    xmlSerializer.Serialize(xmlWriter, value);

                    var sb = new StringBuilder($"{Environment.NewLine}{stringWriter}");

                    sb.Insert(0, xmlDeclaration);

                    return sb.ToString();
                }
            }
0 голосов
/ 09 января 2017

Как говорится в принятом ответе, StringWriter - это UTF-16 (Unicode) по умолчанию и в дизайне. Если вы хотите сделать это, получив в конце строку UTF-8, я могу дать вам два способа сделать это:

Решение № 1 (не очень эффективно, плохая практика, но выполняет свою работу): Скопируйте его в текстовый файл и прочитайте обратно, удалите файл (возможно, подходит только для маленькие файлы, если вы вообще хотите это сделать - просто хотели показать, что это возможно!)

public static string SerializeObject<T>(this T value)
{
    var serializer = new XmlSerializer(typeof(T));           
    var settings = new XmlWriterSettings
                   {
                    Encoding = new UTF8Encoding(true), 
                    Indent = false, 
                    OmitXmlDeclaration = false,
                    NewLineHandling = NewLineHandling.None
                   };


    using(var xmlWriter = XmlWriter.Create("MyFile.xml", settings)) 
    {
        serializer.Serialize(xmlWriter, value);
    }

    XmlDocument xml = new XmlDocument();
    xml.Load("MyFile.xml");
    byte[] bytes = Encoding.UTF8.GetBytes(xml.OuterXml);        
    File.Delete("MyFile.xml");

    return Encoding.UTF8.GetString(bytes);

}

Решение № 2 (лучше, проще, более элегантное решение!): Сделайте так, как у вас, используя StringWriter, но используйте его свойство Encoding, чтобы установить его в UTF-8:

public static string SerializeObject<T>(this T value)
{
    var serializer = new XmlSerializer(typeof(T));           
    var settings = new XmlWriterSettings
                   {
                    Encoding = new UTF8Encoding(true), 
                    Indent = false, 
                    OmitXmlDeclaration = false,
                    NewLineHandling = NewLineHandling.None
                   };

    using(var stringWriter = new UTF8StringWriter())
    {
        using(var xmlWriter = XmlWriter.Create(stringWriter, settings)) 
        {
            serializer.Serialize(xmlWriter, value);
        }

        return stringWriter.ToString();
    }
}

public class UTF8StringWriter : StringWriter
{
    public override Encoding Encoding
    {
        get
        {
            return Encoding.UTF8;
        }
    }
}
...