如何在.NET(C#)中将字符串转换为字节[]而不手动指定特定编码?
我要加密字符串。我可以在不进行转换的情况下对其进行加密,但我仍然想知道为什么编码会在这里发挥作用。
此外,为什么还要考虑编码?我不能简单地获取字符串存储的字节数吗?为什么依赖字符编码?
如何在.NET(C#)中将字符串转换为字节[]而不手动指定特定编码?
我要加密字符串。我可以在不进行转换的情况下对其进行加密,但我仍然想知道为什么编码会在这里发挥作用。
此外,为什么还要考虑编码?我不能简单地获取字符串存储的字节数吗?为什么依赖字符编码?
当前回答
OP的问题:“如何在.NET(C#)中将字符串转换为字节数组?”
您可以使用以下代码:
static byte[] ConvertString (string s) {
return new byte[0];
}
作为一个好处,编码无关紧要!哦,等等,这是一个ecoding。。。它只是微不足道的,而且损耗很大。
其他回答
代码如下:
// Input string.
const string input = "Dot Net Perls";
// Invoke GetBytes method.
// ... You can store this array as a field!
byte[] array = Encoding.ASCII.GetBytes(input);
// Loop through contents of the array.
foreach (byte element in array)
{
Console.WriteLine("{0} = {1}", element, (char)element);
}
两种方式:
public static byte[] StrToByteArray(this string s)
{
List<byte> value = new List<byte>();
foreach (char c in s.ToCharArray())
value.Add(c.ToByte());
return value.ToArray();
}
And,
public static byte[] StrToByteArray(this string s)
{
s = s.Replace(" ", string.Empty);
byte[] buffer = new byte[s.Length / 2];
for (int i = 0; i < s.Length; i += 2)
buffer[i / 2] = (byte)Convert.ToByte(s.Substring(i, 2), 16);
return buffer;
}
我倾向于使用最下面的一个比最上面的一个更频繁,还没有对它们的速度进行基准测试。
如果您使用的是.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>意味着如果需要执行变异,必须创建一个副本,因为字符串是不可变的。
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());
关键问题是字符串中的字形需要32位(字符代码为16位),但字节只有8位可用。一对一映射不存在,除非您将自己限制为仅包含ASCII字符的字符串。System.Text.Encoding有很多方法可以将字符串映射到byte[],您需要选择一种方法来避免信息丢失,并且当您的客户端需要将byte[]映射回字符串时,它很容易使用。
Utf8是一种流行的编码方式,它紧凑而无损耗。