如何在.NET(C#)中将字符串转换为字节[]而不手动指定特定编码?
我要加密字符串。我可以在不进行转换的情况下对其进行加密,但我仍然想知道为什么编码会在这里发挥作用。
此外,为什么还要考虑编码?我不能简单地获取字符串存储的字节数吗?为什么依赖字符编码?
如何在.NET(C#)中将字符串转换为字节[]而不手动指定特定编码?
我要加密字符串。我可以在不进行转换的情况下对其进行加密,但我仍然想知道为什么编码会在这里发挥作用。
此外,为什么还要考虑编码?我不能简单地获取字符串存储的字节数吗?为什么依赖字符编码?
当前回答
字符既是字体表的查找键,也是词汇传统,如排序、大小写版本等。
因此,字符不是字节(8位),字节不是字符。特别是,一个字节的256个排列不能容纳某些书面语言中的数千个符号,更不用说所有语言了。因此,已经设计了各种编码字符的方法。某些编码用于特定类别的语言(ASCII编码);使用代码页的多种语言(扩展ASCII);或者,雄心勃勃地,通过根据需要选择性地包括额外的字节,Unicode来实现所有语言。
在系统(如.NET框架)中,字符串表示特定的字符编码。在.NET中,此编码为Unicode。由于框架默认读取和写入Unicode,因此在.NET中通常不需要处理字符编码。
然而,一般来说,要从字节流将字符串加载到系统中,您需要知道源编码,从而正确解释并随后翻译它(否则代码将被视为已在系统的默认编码中,从而呈现乱码)。类似地,当字符串被写入外部源时,它将以特定的编码被写入。
其他回答
bytes[] buffer = UnicodeEncoding.UTF8.GetBytes(string something); //for converting to UTF then get its bytes
bytes[] buffer = ASCIIEncoding.ASCII.GetBytes(string something); //for converting to ascii then get its bytes
LINQ的简单代码
string s = "abc"
byte[] b = s.Select(e => (byte)e).ToArray();
编辑:如下所述,这不是一个好方法。
但您仍然可以使用它来理解LINQ,并使用更合适的编码:
string s = "abc"
byte[] b = s.Cast<byte>().ToArray();
其他人已经回答了您问题的第一部分(如何获取字节):查看System.Text.Encoding命名空间。
我将回答您的后续问题:为什么需要选择编码?为什么不能从字符串类本身获得这些信息?
答案分为两部分。
首先,字符串类内部使用的字节并不重要,只要假设它们存在,就可能引入错误。
如果您的程序完全在.Net世界中,那么您根本不需要担心获取字符串的字节数组,即使您正在通过网络发送数据。相反,请使用.Net Serialization来担心数据传输问题。您不再担心实际的字节数:Serialization格式化程序会为您提供。
另一方面,如果您将这些字节发送到某个无法保证将从.Net序列化流中提取数据的地方,该怎么办?在这种情况下,您确实需要担心编码问题,因为显然,这个外部系统关心编码问题。同样,字符串使用的内部字节无关紧要:您需要选择一种编码,以便在接收端明确该编码,即使它与.Net内部使用的编码相同。
我理解,在这种情况下,您可能更希望在可能的情况下使用字符串变量存储在内存中的实际字节,这样可以节省创建字节流的工作量。然而,我告诉你,与确保输出在另一端被理解,并保证编码必须明确相比,这并不重要。此外,如果您真的想匹配内部字节,您可以只选择Unicode编码,从而节省性能。
这让我进入第二部分。。。选择Unicode编码就是告诉.Net使用底层字节。您确实需要选择这种编码,因为当一些新的Unicode Plus问世时,.Net运行时需要自由使用这种更新、更好的编码模型,而不会破坏您的程序。但是,目前(以及可预见的未来),只要选择Unicode编码就可以满足您的需要。
理解字符串必须重写为线也是很重要的,即使使用匹配的编码,也至少需要对位模式进行一些转换。计算机需要考虑诸如Big vs Little Endian、网络字节顺序、分组化、会话信息等。
关键问题是字符串中的字形需要32位(字符代码为16位),但字节只有8位可用。一对一映射不存在,除非您将自己限制为仅包含ASCII字符的字符串。System.Text.Encoding有很多方法可以将字符串映射到byte[],您需要选择一种方法来避免信息丢失,并且当您的客户端需要将byte[]映射回字符串时,它很容易使用。
Utf8是一种流行的编码方式,它紧凑而无损耗。
如果您真的想要一个字符串的基本字节的副本,可以使用下面这样的函数。然而,你不应该继续阅读以找出原因。
[DllImport(
"msvcrt.dll",
EntryPoint = "memcpy",
CallingConvention = CallingConvention.Cdecl,
SetLastError = false)]
private static extern unsafe void* UnsafeMemoryCopy(
void* destination,
void* source,
uint count);
public static byte[] GetUnderlyingBytes(string source)
{
var length = source.Length * sizeof(char);
var result = new byte[length];
unsafe
{
fixed (char* firstSourceChar = source)
fixed (byte* firstDestination = result)
{
var firstSource = (byte*)firstSourceChar;
UnsafeMemoryCopy(
firstDestination,
firstSource,
(uint)length);
}
}
return result;
}
这个函数会很快地得到字符串下面的字节的副本。您将以任何方式在系统上编码这些字节。这种编码几乎可以肯定是UTF-16LE,但这是一个您不必关心的实现细节。
打电话会更安全、更简单、更可靠,
System.Text.Encoding.Unicode.GetBytes()
这很可能会产生相同的结果,更容易键入,字节将往返,Unicode中的字节表示也可以,调用
System.Text.Encoding.Unicode.GetString()