Encodage.UTF8.GetString ne tient pas compte du préambule/BOM
.NET, je suis en train d'utiliser Encoding.UTF8.GetString méthode, qui prend un tableau d'octets, et la convertit en un string.
on dirait que cette méthode ignore le BOM (Byte Order Mark), qui pourrait être une partie d'une représentation binaire légitime D'une chaîne UTF8, et le prend comme un caractère.
je sais que je peux utiliser un TextReader pour digérer le BOM comme nécessaire, mais j'ai pensé que la méthode GetString devrait être une sorte de macro qui fait notre code plus court.
Est-ce que je rate quelque chose? Est-ce comme intentionnellement?
voici un code de reproduction:
static void Main(string[] args)
{
    string s1 = "abc";
    byte[] abcWithBom;
    using (var ms = new MemoryStream())
    using (var sw = new StreamWriter(ms, new UTF8Encoding(true)))
    {
        sw.Write(s1);
        sw.Flush();
        abcWithBom = ms.ToArray();
        Console.WriteLine(FormatArray(abcWithBom)); // ef, bb, bf, 61, 62, 63
    }
    byte[] abcWithoutBom;
    using (var ms = new MemoryStream())
    using (var sw = new StreamWriter(ms, new UTF8Encoding(false)))
    {
        sw.Write(s1);
        sw.Flush();
        abcWithoutBom = ms.ToArray();
        Console.WriteLine(FormatArray(abcWithoutBom)); // 61, 62, 63
    }
    var restore1 = Encoding.UTF8.GetString(abcWithoutBom);
    Console.WriteLine(restore1.Length); // 3
    Console.WriteLine(restore1); // abc
    var restore2 = Encoding.UTF8.GetString(abcWithBom);
    Console.WriteLine(restore2.Length); // 4 (!)
    Console.WriteLine(restore2); // ?abc
}
private static string FormatArray(byte[] bytes1)
{
    return string.Join(", ", from b in bytes1 select b.ToString("x"));
}
3 réponses
il semble que cette méthode ignore le BOM (Byte Order Mark), qui pourrait faire partie d'une représentation binaire légitime D'une chaîne UTF8, et le prend comme un caractère.
on ne dirait pas qu'il "l'ignore" du tout - il le convertit fidèlement au caractère BOM. C'est ce qu'il est, après tout.
Si vous voulez faire  code ignore le BOM dans n'importe quelle chaîne qu'il convertit, c'est à vous de le faire... ou de l'utilisation StreamReader.
Notez que si vous  utiliser Encoding.GetBytes suivi de Encoding.GetString ou utiliser StreamWriter suivi de StreamReader, les deux formes produiront puis avaleront ou ne produiront pas le BOM. C'est seulement quand vous mélangez en utilisant un StreamWriter (qui utilise Encoding.GetPreamble) avec un lien direct Encoding.GetString appelez que vous finissez avec le caractère" extra".
basé sur la réponse de Jon Skeet (merci!), c'est la façon dont je l'ai fait:
var memoryStream = new MemoryStream(byteArray);
var s = new StreamReader(memoryStream).ReadToEnd();
notez que cela ne fonctionnera probablement de manière fiable que s'il y a un BOM dans le tableau des octets que vous lisez. Si non, vous pourriez vouloir regarder dans un autre StreamReader surcharge du constructeur qui prend un paramètre D'encodage pour que vous puissiez lui dire ce que contient le tableau des octets.
je sais que je suis un peu en retard à la fête, mais voici le code, je suis en utilisant (n'hésitez pas à l'adapter pour C#) si vous avez besoin de:
 Public Function Serialize(Of YourXMLClass)(ByVal obj As YourXMLClass,
                                                      Optional ByVal omitXMLDeclaration As Boolean = True,
                                                      Optional ByVal omitXMLNamespace As Boolean = True) As String
        Dim serializer As New XmlSerializer(obj.GetType)
        Using memStream As New MemoryStream()
            Dim settings As New XmlWriterSettings() With {
                    .Encoding = Encoding.UTF8,
                    .Indent = True,
                    .OmitXmlDeclaration = omitXMLDeclaration}
            Using writer As XmlWriter = XmlWriter.Create(memStream, settings)
                Dim xns As New XmlSerializerNamespaces
                If (omitXMLNamespace) Then xns.Add("", "")
                serializer.Serialize(writer, obj, xns)
            End Using
            Return Encoding.UTF8.GetString(memStream.ToArray())
        End Using
    End Function
 Public Function Deserialize(Of YourXMLClass)(ByVal obj As YourXMLClass, ByVal xml As String) As YourXMLClass
        Dim result As YourXMLClass
        Dim serializer As New XmlSerializer(GetType(YourXMLClass))
        Using memStream As New MemoryStream()
            Dim bytes As Byte() = Encoding.UTF8.GetBytes(xml.ToArray)
            memStream.Write(bytes, 0, bytes.Count)
            memStream.Seek(0, SeekOrigin.Begin)
            Using reader As XmlReader = XmlReader.Create(memStream)
                result = DirectCast(serializer.Deserialize(reader), YourXMLClass)
            End Using
        End Using
        Return result
    End Function