【问题标题】:Converting string to byte[] creates zero character将字符串转换为 byte[] 创建零字符
【发布时间】:2012-12-20 08:25:24
【问题描述】:

在这个转换函数中

public static byte[] GetBytes(string str)
{
    byte[] bytes = new byte[str.Length * sizeof(char)];
    System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
    return bytes;
}

byte[] test = GetBytes("abc");

结果数组包含零个字符

test = [97, 0, 98, 0, 99, 0]

当我们将 byte[] 转换回字符串时,结果是

string test = "a b c "

我们如何使它不会产生那些零

【问题讨论】:

  • 当您将字符复制到字节数组中时,您似乎故意创建了这些零。您想要哪种编码? ASCII? UTF-8?
  • ToCharArray,顾名思义,返回 char[]。一个 char 是 16 位,即 2 个字节。因此,即使对于简单的 ASCII 文本,您也会得到一个值为 0 的附加字节。
  • @strike_noir 看看我更新的答案。

标签: c# arrays string char byte


【解决方案1】:

首先让我们看看你的代码做错了什么。 char 是 .NET 框架中的 16 位(2 字节)。这意味着当您编写sizeof(char) 时,它会返回2str.Length1,所以实际上你的代码将是 byte[] bytes = new byte[2] 是相同的 byte[2]。因此,当您使用Buffer.BlockCopy() 方法时,实际上是将2 字节从源数组复制到目标数组。这意味着如果您的字符串为" ",您的GetBytes() 方法将返回bytes[0] = 32bytes[1] = 0

尝试改用Encoding.ASCII.GetBytes()

当在派生类中被覆盖时,对所有字符进行编码 将指定的字符串转换成字节序列。

const string input = "Soner Gonul";

byte[] array = Encoding.ASCII.GetBytes(input);

foreach ( byte element in array )
{
     Console.WriteLine("{0} = {1}", element, (char)element);
}

输出:

83 = S
111 = o
110 = n
101 = e
114 = r
32 =
71 = G
111 = o
110 = n
117 = u
108 = l

【讨论】:

    【解决方案2】:

    为了消除您对答案的困惑,C# 中的 char 类型需要 2 个字节。因此,string.toCharArray() 返回一个数组,其中每个项目占用 2 个字节的存储空间。在复制到每个项目占用 1 个字节存储空间的字节数组时,会发生数据丢失。因此,结果中出现零。
    正如建议的那样,Encoding.ASCII.GetBytes 是一个更安全的选择。

    【讨论】:

    • 没有数据丢失,它实际上和Encoding.Unicode.GetBytes一样,编码为UTF16 Little Endian。
    【解决方案3】:

    实际上.net(至少对于 4.0)在使用 BinaryWriter 序列化时会自动更改 char 的大小

    UTF-8 字符有可变长度(可能不是 1 个字节),ASCII 字符有 1 个字节

    'ē' = 2 个字节

    'e' = 1 字节

    使用时一定要牢记

    BinaryReader.ReadChars(stream)
    

    如果单词 "ēvalds" = 7 字节大小将不同于 "evalds" = 6 字节

    【讨论】:

    • "UTF-8 字符有 2 个字节"... 什么? UTF-8 是一种可变长度编码。
    【解决方案4】:

    (97,0) 是 'a' 的 Unicode 表示。 Unicode 以两个字节表示每个字符。所以你不能删除零。但是您可以将编码更改为 ASCII。尝试以下将字符串转换为字节[]。

    byte[] array = Encoding.ASCII.GetBytes(input);
    

    【讨论】:

      【解决方案5】:

      尝试明确指定Encoding。您可以使用下一个代码将字符串转换为具有指定编码的字节

      byte[] bytes = System.Text.Encoding.ASCII.GetBytes("abc");
      

      如果您打印字节的内容,您将得到不包含零的{ 97, 98, 99 },如您的示例所示 在您的示例中,每个符号使用 16 位的默认编码。可以通过打印

      的结果来成为观察者
      System.Text.Encoding.Unicode.GetBytes("abc"); // { 97, 0, 98, 0, 99, 0 }
      

      然后在转换回来的时候,你应该选择合适的编码:

      string str = System.Text.Encoding.ASCII.GetString(bytes);
      Console.WriteLine (str);
      

      如您预期的那样打印"abc"

      【讨论】:

      • 或者使用 Unicode 编码从他从 GetBytes 获得的内容转换回来:string str = System.Text.Encoding.Unicode.GetString(bytes); 然后它也应该适用于非 Ascii。尽管如此,您仍应始终指定编码方式:byte[] bytes = System.Text.Encoding.Unicode.GetBytes("abc"); 请注意,如果您打算进行网络和切换字节序或使用 C# 以外的其他语言,则默认的 UnicodeEncoding 是小端。
      猜你喜欢
      • 1970-01-01
      • 2013-01-17
      • 2015-09-04
      • 1970-01-01
      • 1970-01-01
      • 2014-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多