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

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

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


当前回答

随着C#7.2发布的Span<T>的出现,将字符串的底层内存表示捕获到托管字节数组中的规范技术是:

byte[] bytes = "rubbish_\u9999_string".AsSpan().AsBytes().ToArray();

将其转换回去应该是一件不容易的事,因为这意味着您实际上正在以某种方式解释数据,但为了完整性:

string s;
unsafe
{
    fixed (char* f = &bytes.AsSpan().NonPortableCast<byte, char>().DangerousGetPinnableReference())
    {
        s = new string(f);
    }
}

NonPortableCast和DangerousGetPinnableReference这两个名称应该进一步证明您可能不应该这样做。

注意,使用Span<T>需要安装System.Memory NuGet包。

无论如何,实际的原始问题和后续评论暗示底层内存没有被“解释”(我假设这意味着没有修改或读取,超出了按原样编写的需要),这表明应该使用Stream类的某些实现,而不是将数据作为字符串进行推理。

其他回答

公认的答案非常非常复杂。为此,请使用包含的.NET类:

const string data = "A string with international characters: Norwegian: ÆØÅæøå, Chinese: 喂 谢谢";
var bytes = System.Text.Encoding.UTF8.GetBytes(data);
var decoded = System.Text.Encoding.UTF8.GetString(bytes);

如果你不需要。。。

C#将字符串转换为字节数组:

public static byte[] StrToByteArray(string str)
{
   System.Text.UTF8Encoding  encoding=new System.Text.UTF8Encoding();
   return encoding.GetBytes(str);
}

从字节[]到字符串:

        return BitConverter.ToString(bytes);

OP的问题:“如何在.NET(C#)中将字符串转换为字节数组?”

您可以使用以下代码:

static byte[] ConvertString (string s) {
    return new byte[0];
}

作为一个好处,编码无关紧要!哦,等等,这是一个ecoding。。。它只是微不足道的,而且损耗很大。

这是一个流行的问题。重要的是要了解作者所问的问题,以及它与最常见的需求不同。为了防止在不需要的地方滥用代码,我首先回答了后者。

共同需求

每个字符串都有一个字符集和编码。将System.String对象转换为System.Byte数组时,仍有字符集和编码。对于大多数用途,您可以知道需要哪个字符集和编码,.NET使“复制并转换”变得简单。只需选择适当的encoding类即可。

// using System.Text;
Encoding.UTF8.GetBytes(".NET String to byte array")

转换可能需要处理目标字符集或编码不支持源中的字符的情况。您有一些选择:异常、替换或跳过。默认策略是替换“?”。

// using System.Text;
var text = Encoding.ASCII.GetString(Encoding.ASCII.GetBytes("You win €100")); 
                                                      // -> "You win ?100"

显然,转换不一定是无损的!

注意:对于System.String,源字符集是Unicode。

唯一令人困惑的是,.NET使用字符集的名称作为该字符集的一个特定编码的名称。编码。Unicode应称为Encoding.UTF16。

这就是大多数用法。如果这正是你所需要的,请停止阅读这里。如果您不了解编码是什么,请参阅有趣的Joel Spolsky文章。

特定需求

现在,作者提出的问题是,“每个字符串都存储为一个字节数组,对吗?为什么我不能简单地拥有这些字节?”

他不想改变信仰。

根据C#规范:

C#中的字符和字符串处理使用Unicode编码。字符类型表示UTF-16代码单元,字符串类型表示UTF-16代码单元序列。

因此,我们知道,如果我们请求空转换(即,从UTF-16到UTF-16),我们将得到所需的结果:

Encoding.Unicode.GetBytes(".NET String to byte array")

但为了避免提及编码,我们必须采用另一种方式。如果可以接受中间数据类型,则有一个概念上的快捷方式:

".NET String to byte array".ToCharArray()

这并不能为我们提供所需的数据类型,但Mehrad的答案显示了如何使用BlockCopy将此Char数组转换为Byte数组。然而,这将复制字符串两次!而且,它也显式地使用特定于编码的代码:数据类型System.Char。

获取存储字符串的实际字节的唯一方法是使用指针。fixed语句允许获取值的地址。根据C#规范:

[对于]字符串类型的表达式。。。初始值设定项计算字符串中第一个字符的地址。

为此,编译器使用RuntimeHelpers.OffsetToStringData跳过字符串对象的其他部分编写代码。因此,要获取原始字节,只需创建一个指向字符串的指针并复制所需的字节数。

// using System.Runtime.InteropServices
unsafe byte[] GetRawBytes(String s)
{
    if (s == null) return null;
    var codeunitCount = s.Length;
    /* We know that String is a sequence of UTF-16 code units 
       and such code units are 2 bytes */
    var byteCount = codeunitCount * 2; 
    var bytes = new byte[byteCount];
    fixed(void* pRaw = s)
    {
        Marshal.Copy((IntPtr)pRaw, bytes, 0, byteCount);
    }
    return bytes;
}

正如@CodesInChaus所指出的,结果取决于机器的端序。但问题的作者并不关心这一点。