如何在.NET(C#)中将字符串转换为字节[]而不手动指定特定编码?

我要加密字符串。我可以在不进行转换的情况下对其进行加密,但我仍然想知道为什么编码会在这里发挥作用。

此外,为什么还要考虑编码?我不能简单地获取字符串存储的字节数吗?为什么依赖字符编码?


当前回答

// C# to convert a string to a byte array.
public static byte[] StrToByteArray(string str)
{
    System.Text.ASCIIEncoding  encoding=new System.Text.ASCIIEncoding();
    return encoding.GetBytes(str);
}


// C# to convert a byte array to a string.
byte [] dBytes = ...
string str;
System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
str = enc.GetString(dBytes);

其他回答

计算机只理解原始二进制数据,原始比特。一位是二进制数字:0或1。8位数字是一个字节。一个字节是介于0和255之间的数字。

ASCII是一种将数字转换为字符的表格。0到31之间的数字是控件:制表符、换行符和其他。32到126之间的数字为可打印字符:字母a,数字1,%符号,下划线_

因此,对于ASCII,有33个控制字符和95个可打印字符。

ASCII是当今最常用的字符编码。Unicode表的第一个条目是ASCII,并与ASCII字符集匹配。

ASCII是一个7位字符集。介于0和127之间的数字。使用8位,我们可以达到255位。

ASCII最常见的替代品是EBCDIC,它与ASCII不兼容,今天仍然存在于IBM计算机和数据库中。

1字节,因此8位数字是当今计算机科学中最常用的单位。1字节是介于0和255之间的数字。

ASCII为0到127之间的每个数字定义了一个含义。

与128和255之间的数字相关联的字符取决于所使用的字符编码。目前广泛使用的两种字符编码是windows1252和UTF-8。

在windows1252中,欧元符号对应的数字是128。1字节:[A0]。在Unicode数据库中,欧元符号是数字8364。

现在我给你电话8364。两个字节:[20,AC]。在UTF-8中,欧元符号是数字14844588。三个字节:[E282AC]。

现在我给你一些原始数据。假设20AC。是两个windows1252字符:£还是一个Unicode€符号?

我给你一些原始数据。e282交流。82是windows1252中未分配的字符,因此它可能不是windows1252。它可能是macRoman“”C“”或OEM 437“”或UTF-8“€”符号。

根据字符编码的特性和统计数据,可以猜测原始字节流的编码,但没有可靠的方法。128到255之间的数字在UTF-8中是无效的。é在某些语言(法语)中很常见,因此如果您看到许多字节的值E9被字母包围,那么它可能是一个windows1252编码字符串,E9字节表示é字符。

当您有一个表示字符串的原始字节流时,了解匹配的编码比猜测要好得多。

下面是曾经被广泛使用的各种编码中的一个原始字节的屏幕截图。

如何在.NET(C#)中将字符串转换为字节[]而不手动指定特定编码?

NET中的字符串将文本表示为UTF-16代码单元的序列,因此字节已经在UTF-16中的内存中编码。

Mehrad的回答

您可以使用Mehrad的答案,但它实际上使用了编码,因为字符是UTF-16。它调用ToCharArray,通过查看源代码创建一个char[]并将内存直接复制到它。然后,它将数据复制到同样分配的字节数组中。因此,在后台,它复制了两次底层字节,并分配了一个在调用后不使用的字符数组。

Tom Blodget的回答

Tom Blodget的答案比Mehrad快20-30%,因为它跳过了分配一个字符数组并将字节复制到其中的中间步骤,但它需要使用/safe选项进行编译。如果你绝对不想使用编码,我认为这是正确的方法。如果将加密登录放在固定块中,甚至不需要分配单独的字节数组并将字节复制到其中。

此外,为什么要考虑编码?我不能简单地获取字符串存储的字节数吗?为什么依赖字符编码?

因为这是正确的方法。字符串是一个抽象。

如果“字符串”包含无效字符,使用编码可能会给您带来麻烦,但这不应该发生。如果将数据输入到字符串中包含无效字符,则说明操作错误。您可能应该首先使用字节数组或Base64编码。

如果使用System.Text.Encoding.Unicode,代码将更具弹性。您不必担心运行代码的系统的端序。您不必担忧下一版本的CLR是否会使用不同的内部字符编码。

我认为问题不在于你为什么要担心编码,而是你为什么要忽略它而使用其他东西。编码旨在表示字节序列中字符串的抽象。System.Text.Encoding.Unicode将为您提供一个小端字节顺序编码,并将在现在和将来的每个系统上执行相同的编码。

这取决于你想要的字节

这是因为,正如泰勒所恰当地说的,“字符串不是纯数据。它们也有信息。”在这种情况下,信息是创建字符串时假定的编码。

假设您有二进制数据(而不是文本)存储在字符串中

这是基于OP对自己问题的评论,如果我理解OP在用例中的提示,这是正确的问题。

由于上面提到的假设编码,将二进制数据存储在字符串中可能是错误的方法!无论哪个程序或库将二进制数据存储在字符串中(而不是更合适的byte[]数组),在战斗开始之前就已经失败了。如果他们以REST请求/响应或任何必须传输字符串的方式向您发送字节,Base64将是正确的方法。

如果您有一个编码未知的文本字符串

其他人都错误地回答了这个错误的问题。

如果字符串看起来不错,只需选择一个编码(最好是以UTF开头的编码),使用相应的System.Text.encoding。???。GetBytes()函数,并告诉给谁您选择了哪种编码。

我不确定,但我认为字符串将其信息存储为一个Chars数组,这对字节来说效率很低。具体来说,Char的定义是“表示Unicode字符”。

以以下示例为例:

String str = "asdf éß";
String str2 = "asdf gh";
EncodingInfo[] info =  Encoding.GetEncodings();
foreach (EncodingInfo enc in info)
{
    System.Console.WriteLine(enc.Name + " - " 
      + enc.GetEncoding().GetByteCount(str)
      + enc.GetEncoding().GetByteCount(str2));
}

请注意,在这两种情况下,Unicode答案都是14个字节,而UTF-8答案第一种只有9个字节,第二种只有7个字节。

因此,如果您只想要字符串所使用的字节,只需使用Encoding.Unicode,但存储空间会很低。

byte[] strToByteArray(string str)
{
    System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
    return enc.GetBytes(str);
}