首页 > 解决方案 > C# - .NET 4.7 - 流编码问题 - 不正确读取 unicode 和 ascii 字符

问题描述

我编写了一个小函数来将程序数据写入流。大概这个流可以去任何地方:到一个文件(当前用例),到一个套接字,到内存,任何地方。所以很自然地,我只是使用默认编码编写数据。经过一些测试,它引发了编码异常。所以我不得不将字符串编码成一个字节数组并写入字节。

但是有一个问题:写入的字节在读取时不会解码回相同的字符串。如果我们使用可在键盘上键入的 ascii 字符,这不是问题,但当我们开始使用 unicode 字符和显然是 27 个 ascii 字符时,它确实会成为问题。

这是测试用例。我鼓励你运行它:

using System.IO;
using System.Text;
using System;

public class TestCase
{
    public static void Main(string[] args)
    {
        readwrite_tests();
    }
    
    public static void readwrite_tests()
    {
        string temps, result;
        ulong count = 0;
        byte[] buffer = new byte[sizeof(char) * 4];

        using(MemoryStream mem = new MemoryStream(buffer))
        using (BinaryReader reader = new BinaryReader(mem, Encoding.Default))
        using (BinaryWriter writer = new BinaryWriter(mem, Encoding.Default))
        {
            for(char c = char.MinValue; c <= 0xfff; ++c)
            {
                temps = c.ToString();
                if(mem.Position != 0) mem.Seek(0, SeekOrigin.Begin);
                result = read_write(temps, writer, reader, mem);
                if(!result.Equals(temps))
                {
                    //Console.Write("char: " + c.ToString() + "  int: " + ((int)c).ToString() +
                    //    "\tread: " + result + "  int: [");
                    //foreach (char d in result) Console.Write(((int)d).ToString() + " ");
                    //Console.WriteLine("]");
                    ++count;
                }
            }
        }
        Console.WriteLine("Incorrect reads is " + count.ToString() + 
            " out of " + int.Parse("fff", System.Globalization.NumberStyles.HexNumber));
        Console.WriteLine("Correct Reads: " + ((ulong)int.Parse("fff", System.Globalization.NumberStyles.HexNumber) - count));
    }

    public static string read_write(string s, BinaryWriter writer, BinaryReader reader, Stream stream)
    {
        string read_string = "";

        byte[] bytes = Encoding.Default.GetBytes(s);
        writer.Write(bytes.Length);
        writer.Write(bytes);
        stream.Seek(0, SeekOrigin.Begin);
        try
        {
            read_string = Encoding.Default.GetString(reader.ReadBytes(reader.ReadInt32()));
        }
        catch(EndOfStreamException)
        {
        }
        return read_string;
    }
}

请在https://dotnetfiddle.net/上运行此程序以观察结果。

如您所见,我们只有 238 个正确读数。我不明白为什么会这样。让我知道是否可以提供更多信息,但我已经尝试了很多,包括改用 JsonSerializer(结果相同)。

标签: c#serializationiostream

解决方案


选择一个明确的编码并坚持下去。最好是 UTF-8。在 .NET 4.7.2 中,默认编码(至少在 .NET Fiddle 上)是西欧 (Windows)。在 .NET 5 中是 Unicode (UTF-8)。

如果您不相信我,请将此行添加到您的 read_write 例程中:

Console.WriteLine(Encoding.Default.EncodingName);

推荐阅读