如何在.NET(C#)中将字符串转换为字节[]而不手动指定特定编码?
我要加密字符串。我可以在不进行转换的情况下对其进行加密,但我仍然想知道为什么编码会在这里发挥作用。
此外,为什么还要考虑编码?我不能简单地获取字符串存储的字节数吗?为什么依赖字符编码?
如何在.NET(C#)中将字符串转换为字节[]而不手动指定特定编码?
我要加密字符串。我可以在不进行转换的情况下对其进行加密,但我仍然想知道为什么编码会在这里发挥作用。
此外,为什么还要考虑编码?我不能简单地获取字符串存储的字节数吗?为什么依赖字符编码?
当前回答
您需要考虑编码,因为1个字符可以由1个或多个字节(最多约6个)表示,不同的编码将对这些字节进行不同的处理。
Joel对此发表了一篇帖子:
绝对最低限度每个软件开发人员绝对、肯定地必须了解Unicode和字符集(没有借口!)
其他回答
只需使用此选项:
byte[] myByte= System.Text.ASCIIEncoding.Default.GetBytes(myString);
与这里的答案相反,如果不需要解释字节,则不需要担心编码!
正如您提到的,您的目标很简单,就是“获取字符串存储的字节数”。(当然,还要能够根据字节重新构造字符串。)
对于这些目标,我真的不明白为什么人们总是告诉你你需要编码。你当然不需要担心编码。
只需执行以下操作:
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;
}
// Do NOT use on arbitrary bytes; only use on GetBytes's output on the SAME system
static string GetString(byte[] bytes)
{
char[] chars = new char[bytes.Length / sizeof(char)];
System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
return new string(chars);
}
只要你的程序(或其他程序)不试图以某种方式解释字节,而你显然没有提到你打算这样做,那么这种方法就没有错!担心编码只会让你的生活变得更加复杂,没有真正的原因。
这种方法的额外好处:字符串是否包含无效字符无关紧要,因为您仍然可以获取数据并重建原始字符串!
它将以相同的方式进行编码和解码,因为您只是在查看字节。
但是,如果您使用特定的编码,则会给您带来编码/解码无效字符的麻烦。
BinaryFormatter bf = new BinaryFormatter();
byte[] bytes;
MemoryStream ms = new MemoryStream();
string orig = "喂 Hello 谢谢 Thank You";
bf.Serialize(ms, orig);
ms.Seek(0, 0);
bytes = ms.ToArray();
MessageBox.Show("Original bytes Length: " + bytes.Length.ToString());
MessageBox.Show("Original string Length: " + orig.Length.ToString());
for (int i = 0; i < bytes.Length; ++i) bytes[i] ^= 168; // pseudo encrypt
for (int i = 0; i < bytes.Length; ++i) bytes[i] ^= 168; // pseudo decrypt
BinaryFormatter bfx = new BinaryFormatter();
MemoryStream msx = new MemoryStream();
msx.Write(bytes, 0, bytes.Length);
msx.Seek(0, 0);
string sx = (string)bfx.Deserialize(msx);
MessageBox.Show("Still intact :" + sx);
MessageBox.Show("Deserialize string Length(still intact): "
+ sx.Length.ToString());
BinaryFormatter bfy = new BinaryFormatter();
MemoryStream msy = new MemoryStream();
bfy.Serialize(msy, sx);
msy.Seek(0, 0);
byte[] bytesy = msy.ToArray();
MessageBox.Show("Deserialize bytes Length(still intact): "
+ bytesy.Length.ToString());
OP的问题:“如何在.NET(C#)中将字符串转换为字节数组?”
您可以使用以下代码:
static byte[] ConvertString (string s) {
return new byte[0];
}
作为一个好处,编码无关紧要!哦,等等,这是一个ecoding。。。它只是微不足道的,而且损耗很大。
如果您使用的是.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>意味着如果需要执行变异,必须创建一个副本,因为字符串是不可变的。