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

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

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


当前回答

最快的方式

public static byte[] GetBytes(string text)
{
    return System.Text.ASCIIEncoding.UTF8.GetBytes(text);
}

编辑正如Makotosan所说,这是现在最好的方式:

Encoding.UTF8.GetBytes(text)

其他回答

如果您使用的是.NET Core或System.Memory for.NET Framework,则通过Span<T>和Memory<T>有一种非常有效的封送机制,可以有效地将字符串内存重新解释为字节跨度。一旦有了一个字节跨度,就可以自由地封送回另一个类型,或者将该跨度复制到数组中进行序列化。

总结一下其他人的看法:

存储这种序列化的表示形式对系统端序、编译器优化以及正在执行的.NET运行时中字符串的内部表示形式的更改非常敏感。避免长期储存避免在其他环境中反序列化或解释字符串这包括其他机器、处理器体系结构、.NET运行时、容器等。这包括比较、格式化、加密、字符串操作、本地化、字符转换等。避免对字符编码进行假设在实践中,默认编码倾向于UTF-16LE,但编译器/运行时可以选择任何内部表示

实施

public static class MarshalExtensions
{
   public static ReadOnlySpan<byte> AsBytes(this string value) => MemoryMarshal.AsBytes(value.AsSpan());
   public static string AsString(this ReadOnlySpan<byte> value) => new string(MemoryMarshal.Cast<byte, char>(value));
}

实例

static void Main(string[] args)
{
    string str1 = "你好,世界";
    ReadOnlySpan<byte> span = str1.AsBytes();
    string str2 = span.AsString();

    byte[] bytes = span.ToArray();

    Debug.Assert(bytes.Length > 0);
    Debug.Assert(str1 == str2);
}

Furthur洞察

在C++中,这大致相当于reinterpret_cast,而C大致相当于对系统的单词类型(char)的强制转换。

在最新版本的.NET核心运行时(CoreCLR)中,如果您的内存是由CLR分配的,并且跨段不是从非托管内存分配器的指针派生的,则跨段上的操作可以有效地调用编译器内部函数和各种优化,这些优化有时可以消除边界检查,从而在保持内存安全的同时提高性能。

注意事项

这使用CLR支持的机制,该机制从字符串返回ReadOnlyPan<char>;此外,此跨度不一定包含完整的内部字符串布局。ReadOnlySpan<T>意味着如果需要执行变异,必须创建一个副本,因为字符串是不可变的。

由于以下事实,字符串可以通过几种不同的方式转换为字节数组:.NET支持Unicode,Unicode标准化了几种称为UTF的不同编码。它们具有不同长度的字节表示,但在这个意义上是等价的,即当字符串被编码时,它可以被编码回字符串,但如果字符串用一个UTF编码,并且在不同UTF的假设下解码,如果可能会出错。

此外,.NET支持非Unicode编码,但它们在一般情况下无效(只有在实际字符串(如ASCII)中使用有限的Unicode代码点子集时才有效)。在内部,.NET支持UTF-16,但对于流表示,通常使用UTF-8。它也是互联网的事实标准。

毫不奇怪,System.Text.Encoding类是一个抽象类,它支持将字符串序列化为字节数组和反序列化;它的派生类支持具体编码:ASCIIEncoding和四个UTF(System.Text.UnicodeEncoding支持UTF-16)

参考此链接。

对于使用System.Text.Encoding.GetBytes对字节数组进行序列化。对于反向操作,使用System.Text.Encoding.GGetChars。此函数返回字符数组,因此要获取字符串,请使用字符串构造函数System.string(char[])。请参阅本页。

例子:

string myString = //... some string

System.Text.Encoding encoding = System.Text.Encoding.UTF8; //or some other, but prefer some UTF is Unicode is used
byte[] bytes = encoding.GetBytes(myString);

//next lines are written in response to a follow-up questions:

myString = new string(encoding.GetChars(bytes));
byte[] bytes = encoding.GetBytes(myString);
myString = new string(encoding.GetChars(bytes));
byte[] bytes = encoding.GetBytes(myString);

//how many times shall I repeat it to show there is a round-trip? :-)

关键问题是字符串中的字形需要32位(字符代码为16位),但字节只有8位可用。一对一映射不存在,除非您将自己限制为仅包含ASCII字符的字符串。System.Text.Encoding有很多方法可以将字符串映射到byte[],您需要选择一种方法来避免信息丢失,并且当您的客户端需要将byte[]映射回字符串时,它很容易使用。

Utf8是一种流行的编码方式,它紧凑而无损耗。

试试这个,代码更少:

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