如何在.NET(C#)中将字符串转换为字节[]而不手动指定特定编码?
我要加密字符串。我可以在不进行转换的情况下对其进行加密,但我仍然想知道为什么编码会在这里发挥作用。
此外,为什么还要考虑编码?我不能简单地获取字符串存储的字节数吗?为什么依赖字符编码?
如何在.NET(C#)中将字符串转换为字节[]而不手动指定特定编码?
我要加密字符串。我可以在不进行转换的情况下对其进行加密,但我仍然想知道为什么编码会在这里发挥作用。
此外,为什么还要考虑编码?我不能简单地获取字符串存储的字节数吗?为什么依赖字符编码?
当前回答
字符既是字体表的查找键,也是词汇传统,如排序、大小写版本等。
因此,字符不是字节(8位),字节不是字符。特别是,一个字节的256个排列不能容纳某些书面语言中的数千个符号,更不用说所有语言了。因此,已经设计了各种编码字符的方法。某些编码用于特定类别的语言(ASCII编码);使用代码页的多种语言(扩展ASCII);或者,雄心勃勃地,通过根据需要选择性地包括额外的字节,Unicode来实现所有语言。
在系统(如.NET框架)中,字符串表示特定的字符编码。在.NET中,此编码为Unicode。由于框架默认读取和写入Unicode,因此在.NET中通常不需要处理字符编码。
然而,一般来说,要从字节流将字符串加载到系统中,您需要知道源编码,从而正确解释并随后翻译它(否则代码将被视为已在系统的默认编码中,从而呈现乱码)。类似地,当字符串被写入外部源时,它将以特定的编码被写入。
其他回答
为了证明Mehrrad的声音回答有效,他的方法甚至可以持久化未配对的代理字符(其中许多人对我的答案持反对态度,但每个人都有同样的错误,例如System.Text.Encoding.UTF8.GetBytes、System.Text.Encding.Unicode.GetBytes;例如,这些编码方法不能持久化高代理字符d800,而这些方法只是用值fffd替换高代理字符):
using System;
class Program
{
static void Main(string[] args)
{
string t = "爱虫";
string s = "Test\ud800Test";
byte[] dumpToBytes = GetBytes(s);
string getItBack = GetString(dumpToBytes);
foreach (char item in getItBack)
{
Console.WriteLine("{0} {1}", item, ((ushort)item).ToString("x"));
}
}
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;
}
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);
}
}
输出:
T 54
e 65
s 73
t 74
? d800
T 54
e 65
s 73
t 74
尝试使用System.Text.Encoding.UTF8.GetBytes或System.Text.Encding.Unicode.GetBytes,它们只会用值fffd替换高代理项字符
每当这个问题发生变化时,我仍然在想一个序列化程序(无论是来自Microsoft还是来自第三方组件),它可以持久化字符串,即使它包含不成对的代理字符;我时不时地在谷歌上搜索这个:序列化不成对的代理角色.NET。这不会让我失眠,但偶尔有人评论我的答案,说它有缺陷,但他们的答案在不成对的替代角色方面同样有缺陷,这让我很烦。
Darn,Microsoft应该在BinaryFormatter中使用System.Buffer.BlockCopyツ
谢谢!
您需要考虑编码,因为1个字符可以由1个或多个字节(最多约6个)表示,不同的编码将对这些字节进行不同的处理。
Joel对此发表了一篇帖子:
绝对最低限度每个软件开发人员绝对、肯定地必须了解Unicode和字符集(没有借口!)
此外,请解释为什么要考虑编码。我不能简单地获取字符串存储的字节数吗?为什么依赖编码?!!!
因为没有“字符串的字节”这样的东西。
字符串(或更一般的文本)由字符组成:字母、数字和其他符号。这就是全部。然而,计算机对字符一无所知;它们只能处理字节。因此,如果要使用计算机存储或传输文本,需要将字符转换为字节。你是怎么做到的?这里是编码出现的地方。
编码只是将逻辑字符转换为物理字节的惯例。最简单和最著名的编码是ASCII,如果你用英语写作,这就是你所需要的。对于其他语言,您将需要更完整的编码,因为Unicode是当今最安全的选择。
因此,简而言之,尝试“不使用编码获取字符串的字节”与“不使用任何语言编写文本”一样不可能。
顺便说一句,我强烈建议你(以及任何人)阅读这篇小智慧:绝对最低限度每个软件开发人员绝对、积极地必须了解Unicode和字符集(没有借口!)
// C# to convert a string to a byte array.
public static byte[] StrToByteArray(string str)
{
System.Text.ASCIIEncoding encoding=new System.Text.ASCIIEncoding();
return encoding.GetBytes(str);
}
// C# to convert a byte array to a string.
byte [] dBytes = ...
string str;
System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
str = enc.GetString(dBytes);
与这里的答案相反,如果不需要解释字节,则不需要担心编码!
正如您提到的,您的目标很简单,就是“获取字符串存储的字节数”。(当然,还要能够根据字节重新构造字符串。)
对于这些目标,我真的不明白为什么人们总是告诉你你需要编码。你当然不需要担心编码。
只需执行以下操作:
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);
}
只要你的程序(或其他程序)不试图以某种方式解释字节,而你显然没有提到你打算这样做,那么这种方法就没有错!担心编码只会让你的生活变得更加复杂,没有真正的原因。
这种方法的额外好处:字符串是否包含无效字符无关紧要,因为您仍然可以获取数据并重建原始字符串!
它将以相同的方式进行编码和解码,因为您只是在查看字节。
但是,如果您使用特定的编码,则会给您带来编码/解码无效字符的麻烦。