将字符串转换为 byte[] 创建零字符
Posted
技术标签:
【中文标题】将字符串转换为 byte[] 创建零字符【英文标题】:Converting string to byte[] creates zero character 【发布时间】: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? Return file download from byte[]的可能重复 ToCharArray,顾名思义,返回 char[]。一个 char 是 16 位,即 2 个字节。因此,即使对于简单的 ASCII 文本,您也会得到一个值为 0 的附加字节。 @strike_noir 看看我更新的答案。 【参考方案1】:首先让我们看看你的代码做错了什么。 char
是 .NET 框架中的 16 位(2 字节)。这意味着当您编写sizeof(char)
时,它会返回2
。 str.Length
是 1
,所以实际上你的代码将是 byte[] bytes = new byte[2]
是相同的 byte[2]
。因此,当您使用Buffer.BlockCopy()
方法时,实际上是将2
字节从源数组复制到目标数组。这意味着如果您的字符串为" "
,您的GetBytes()
方法将返回bytes[0] = 32
和bytes[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 是小端。以上是关于将字符串转换为 byte[] 创建零字符的主要内容,如果未能解决你的问题,请参考以下文章