如何在.NET(C#)中将字符串转换为字节[]而不手动指定特定编码?
我要加密字符串。我可以在不进行转换的情况下对其进行加密,但我仍然想知道为什么编码会在这里发挥作用。
此外,为什么还要考虑编码?我不能简单地获取字符串存储的字节数吗?为什么依赖字符编码?
如何在.NET(C#)中将字符串转换为字节[]而不手动指定特定编码?
我要加密字符串。我可以在不进行转换的情况下对其进行加密,但我仍然想知道为什么编码会在这里发挥作用。
此外,为什么还要考虑编码?我不能简单地获取字符串存储的字节数吗?为什么依赖字符编码?
当前回答
可以使用以下代码将字符串转换为.NET中的字节数组
string s_unicode = "abcéabc";
byte[] utf8Bytes = System.Text.Encoding.UTF8.GetBytes(s_unicode);
其他回答
LINQ的简单代码
string s = "abc"
byte[] b = s.Select(e => (byte)e).ToArray();
编辑:如下所述,这不是一个好方法。
但您仍然可以使用它来理解LINQ,并使用更合适的编码:
string s = "abc"
byte[] b = s.Cast<byte>().ToArray();
与这里的答案相反,如果不需要解释字节,则不需要担心编码!
正如您提到的,您的目标很简单,就是“获取字符串存储的字节数”。(当然,还要能够根据字节重新构造字符串。)
对于这些目标,我真的不明白为什么人们总是告诉你你需要编码。你当然不需要担心编码。
只需执行以下操作:
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);
}
只要你的程序(或其他程序)不试图以某种方式解释字节,而你显然没有提到你打算这样做,那么这种方法就没有错!担心编码只会让你的生活变得更加复杂,没有真正的原因。
这种方法的额外好处:字符串是否包含无效字符无关紧要,因为您仍然可以获取数据并重建原始字符串!
它将以相同的方式进行编码和解码,因为您只是在查看字节。
但是,如果您使用特定的编码,则会给您带来编码/解码无效字符的麻烦。
当被问及您打算如何处理字节时,您回答:
我将对它进行加密。我可以在不进行转换的情况下对其进行加密,但我仍然想知道为什么编码会在这里发挥作用。给我字节就是我说的。
无论您是否打算通过网络发送加密数据,稍后将其加载回内存,或将其流式传输到另一个进程,您显然都打算在某个时刻对其进行解密。在这种情况下,答案是您正在定义通信协议。通信协议不应根据编程语言及其相关运行时的实现细节来定义。这有几个原因:
您可能需要与以不同语言或运行时实现的流程进行通信。(例如,这可能包括在另一台机器上运行的服务器或将字符串发送到JavaScript浏览器客户端。)该程序将来可以用不同的语言或运行时重新实现。.NET实现可能会更改字符串的内部表示形式。您可能会觉得这听起来有些牵强,但这实际上发生在Java9中,以减少内存使用。.NET没有理由不能效仿。Skeet表明,UTF-16在今天可能不是最佳的,因为表情符号和其他Unicode块也需要2个以上的字节来表示,这增加了内部表示在未来可能发生变化的可能性。
为了进行通信(无论是与完全不同的进程还是将来与相同的程序),您需要严格定义协议,以最大限度地减少使用协议或意外创建错误的难度。依赖于.NET的内部表示并不是一个严格的、明确的,甚至不能保证是一致的定义。标准编码是一个严格的定义,将来不会让您失望。
换句话说,如果不指定编码,就无法满足一致性要求。
如果您发现由于.NET在内部使用了UTF-16或出于其他原因,您的进程的性能明显更好,那么您当然可以选择直接使用UTF-16,但您需要显式选择编码,并在代码中显式执行这些转换,而不是依赖于.NET的内部实现。
因此,选择一种编码并使用它:
using System.Text;
// ...
Encoding.Unicode.GetBytes("abc"); # UTF-16 little endian
Encoding.UTF8.GetBytes("abc")
正如您所看到的,与实现您自己的读写器方法相比,仅使用内置的编码对象实际上也是更少的代码。
代码如下:
// 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);
}
以下是我的String-to-Byte[]转换的不安全实现:
public static unsafe Byte[] GetBytes(String s)
{
Int32 length = s.Length * sizeof(Char);
Byte[] bytes = new Byte[length];
fixed (Char* pInput = s)
fixed (Byte* pBytes = bytes)
{
Byte* source = (Byte*)pInput;
Byte* destination = pBytes;
if (length >= 16)
{
do
{
*((Int64*)destination) = *((Int64*)source);
*((Int64*)(destination + 8)) = *((Int64*)(source + 8));
source += 16;
destination += 16;
}
while ((length -= 16) >= 16);
}
if (length > 0)
{
if ((length & 8) != 0)
{
*((Int64*)destination) = *((Int64*)source);
source += 8;
destination += 8;
}
if ((length & 4) != 0)
{
*((Int32*)destination) = *((Int32*)source);
source += 4;
destination += 4;
}
if ((length & 2) != 0)
{
*((Int16*)destination) = *((Int16*)source);
source += 2;
destination += 2;
}
if ((length & 1) != 0)
{
++source;
++destination;
destination[0] = source[0];
}
}
}
return bytes;
}
它比公认的anwser要快得多,即使没有它那么优雅。以下是我在10000000次迭代中的秒表基准:
[Second String: Length 20]
Buffer.BlockCopy: 746ms
Unsafe: 557ms
[Second String: Length 50]
Buffer.BlockCopy: 861ms
Unsafe: 753ms
[Third String: Length 100]
Buffer.BlockCopy: 1250ms
Unsafe: 1063ms
为了使用它,您必须在项目构建财产中勾选“允许不安全代码”。根据.NET Framework 3.5,此方法也可以用作字符串扩展:
public static unsafe class StringExtensions
{
public static Byte[] ToByteArray(this String s)
{
// Method Code
}
}