27

Encoding.UTF8.GetString.NETでは、バイト配列を取得してそれを。に変換するメソッドを使用しようとしていstringます。

このメソッドは、UTF8文字列の正当なバイナリ表現の一部である可能性があるBOM(Byte Order Mark)を無視し、それを文字として受け取るようです。

必要に応じてを使用しTextReaderてBOMをダイジェストできることはわかっていますが、GetStringメソッドは、コードを短くするマクロのようなものである必要があると思いました。

私は何かが足りないのですか?これは意図的にそうですか?

複製コードは次のとおりです。

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"));
}
4

4 に答える 4

30

このメソッドは、UTF8文字列の正当なバイナリ表現の一部である可能性があるBOM(Byte Order Mark)を無視し、それを文字として受け取るようです。

それを「無視」しているようには見えません。忠実にBOM文字に変換します。結局のところ、それはそれが何であるかです。

コードが変換する文字列のBOMを無視するようにしたい場合は、それを実行するか、またはを使用ますStreamReader

を使用してから使用するか、使用してからを使用する場合、どちらの形式でもBOMが生成されてから飲み込まれるか、生成さEncoding.GetBytesれないことに注意してください。(を使用する)を使用して直接呼び出しを混合した場合にのみ、「余分な」文字が表示されます。Encoding.GetString StreamWriterStreamReaderStreamWriterEncoding.GetPreambleEncoding.GetString

于 2012-07-28T13:47:22.850 に答える
10

Jon Skeetの回答に基づいて(ありがとう!)、これが私がやった方法です。

var memoryStream = new MemoryStream(byteArray);
var s = new StreamReader(memoryStream).ReadToEnd();

これは、読み取り元のバイト配列にBOMがある場合にのみ確実に機能することに注意してください。そうでない場合は、Encodingパラメーターを受け取る別のStreamReaderコンストラクターのオーバーロードを調べて、バイト配列に何が含まれているかを確認することをお勧めします。

于 2013-11-20T15:36:35.240 に答える
5

ストリームを使用したくない人のために、Linqを使用した非常に簡単な解決策を見つけました。

public static string GetStringExcludeBOMPreamble(this Encoding encoding, byte[] bytes)
{
    var preamble = encoding.GetPreamble();
    if (preamble?.Length > 0 && bytes.Length >= preamble.Length && bytes.Take(preamble.Length).SequenceEqual(preamble))
    {
        return encoding.GetString(bytes, preamble.Length, bytes.Length - preamble.Length);
    }
    else
    {
        return encoding.GetString(bytes);
    }
}
于 2018-12-12T10:32:50.220 に答える
0

私はパーティーに少し遅れていることを知っていますが、必要に応じて私が使用しているコードは次のとおりです(C#に自由に適応できます)。

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
于 2015-04-01T18:45:28.433 に答える