How do you convert a string to a byte array in .NET?
我有一个字符串,需要将它转换为.NET中的等效字节数组。
这应该很容易,但我的大脑抽筋了。
您需要使用编码(System.Text.Encoding来告诉.NET您期望的输出。例如,在utf-16(=System.Text.Encoding.Unicode中):
1
| var result = System.Text.Encoding.Unicode.GetBytes(text); |
- 在system.text.encoding中有很多编码,而不仅仅是Unicode编码:请确保您了解您需要哪种编码。
- 乔尔:所以我写了"例如"。;-)但是你的评论当然是有效的。
- :)试图帮助显示非UTF16编码的位置-我可能已经把它写得更好了。
首先,找出你想要的编码方式:你需要先了解一下Unicode。
下一步,找出对应的System.Text.Encoding。我的core.net refcard描述了大多数常见的实例,以及如何获取实例(例如,通过Encoding的静态属性或通过调用Encoding.GetEncoding获取实例)。
最后,确定您是希望所有字节同时进行(这是最简单的工作方式——调用encoding.getbytes(string)一次,然后就完成了),还是需要将其分成块——在这种情况下,您需要使用encoding.getencoder,然后一次编码一点。编码器负责保持调用之间的状态,以防需要中断字符的一半。
- @乔恩斯基特:除非你(或其他人)真的要解释字节,否则你真的不需要编码,是吗?对于压缩、加密、模糊处理等任务,编码似乎有点无关紧要…如果你不需要的话,没有理由经历麻烦。
- @你当然知道。编码定义了从字符串到字节数组的转换所执行的操作。压缩和加密是完全不同的事情。否则,就好像你想将图片保存为文件时,图像格式无关紧要一样——很多不同的图像格式都可以,但根据定义,必须有一种。
- @乔恩斯基特:你就不能说"埃多克斯1"〔0〕吗?谁在乎编码是什么(或者如果字符串的第一个地方甚至有有效的字符),只要你知道你可以通过反向操作以相同的形式得到它?
- @梅尔达:那就用UTF-16了。它仍然是一种编码——只是它是用于char内部的自然编码。(如果你的字符串都是ASCII码的话,你可能会非常关心这个事实,因为它的大小是需要的两倍。)
- @乔斯基特:是的,但我的观点是,用户想要"获取字节"这一事实并不意味着他甚至需要知道"编码"到底意味着什么……只有当他把它们解释成一个黑匣子时,这才重要。(关于空间问题:是的,这显然是一个问题,但通常当你"只想要字节"的时候,这是不相关的,我想情况是这样的。很明显,了解编码是有益的,但是你不需要在这里了解它们,是吗?)
- @不,用户需要知道编码。仅仅因为UTF-16在某种意义上是.NET的自然编码,并不意味着它就是他想要使用的编码。把数据写出来的目的是让它能被再次读取——这需要使用相同的编码。OP提到"等价字节数组"的事实表明,他们不知道编码甚至存在,如果要在文本和二进制表示之间转换,理解编码至关重要。
- 我见过无数人因为不懂编码而未能正确地保存信息。根据我的经验,向他们介绍这个主题比使用Buffer.BlockCopy和假设他们想要的更好。
- @那么,如果字符串中的某个字符在您要"获取字节"的编码中无效(可能是因为其他人给了您该字符串,而您对它的内容不负责),您该怎么办?也许它有私用字符,或者他们甚至没有告诉你编码?使用任何特定的编码都没有意义,因为您的字符可能没有任何转换。相反,如果您只使用我提到的方法,那么字符是否有效并不重要,因为它们无论如何都能正常工作。
- @Mehrdad:字符串没有编码(或者它总是utf-16)。如果它是从UTF-8读取的,那么在内部它仍然以UTF-16结尾。不是你的方法没有使用编码,而是它是隐式的,这在我看来是一件坏事。显然你需要使用适当的编码,但仅仅是试图把问题当作不存在的东西来处理,这在我看来是一个非常糟糕的主意。忽视编码并不是前进的方向。如果要使用UTF-16,请显式使用(Encoding.Unicode)。
- @我不明白你对"一个字符串没有编码(或者它总是utf-16)"的评论……那两个是对立的。System.String必须始终包含utf-16吗?就这一点而言,它必须遵守任何其他特定的编码吗?
- @Mehrdad:它总是char的序列,它本身就是一个utf-16代码单元。(不是Unicode码位,注意。)但例如,谈论"utf-8字符串"是毫无意义的。您可以有"字符串的UTF-8表示"(这将是一个字节数组),但这是另一回事。
- @我不明白。如果您声称string必须始终包含有效的utf-16数据,那么这是错误的("\uFFFF\uFFFF")。如果您声称它不一定包含有效的UTF-16数据,并且它可以用多个可能的编码表示数据,那么我想问一个问题:当您不知道要使用什么编码时,在字符串上使用Encoding.XXX.GetBytes()有什么意义?(这不像是人们给你的每一个string对象的编码,他们传递给你…)
- @这取决于你所说的"有效"是什么意思。根据定义,它始终包含UTF-16代码单元。当然,它们不必映射到定义的Unicode字符…但它们仍然是UTF-16。因此,如果您想表示一个私有范围中的某个值,可以用UTF-16表示,然后在以后转换为相同私有范围字符的UTF-8(或其他)编码。如果您不知道要使用什么编码,则根本不应该转换为字节。这就像要求保存一个图像而不指定图像格式-只需说"不"。
- @琼斯基特:对不起,这是未来的事,不知道我是怎么错过这个评论的…但是,需要加密/压缩用于传输/存储的字符串而不知道(或不关心)要使用什么编码是完全有意义的。在许多类似的场景中,编码根本不需要发挥作用。
- @Mehrdad:可以先压缩,然后解压缩一些字符串的二进制表示,而不需要知道它的编码方式。把压缩后的二进制数据当作文本来处理并不好。每当您想从字符串转换为二进制或从二进制转换为二进制时,您必须知道要使用哪种编码,并且两种方法都要一致。
- @琼斯基特:是的,我也这么说,对吧?只要不尝试解释字节,就不需要担心编码问题。:)
- @梅尔达:但是有人会在以后解释这些字节。你说的对,压缩/加密部分不需要关心,但是不管以后怎么把它变成一个字符串,绝对是这样的……如果没有人能解释这些数据,那就没有什么意义了。所以,是的,您仍然需要选择一种编码,并确保它的使用是一致的。你决定使用哪种编码方式,只要它能对你的所有文本进行编码,就有点武断了,尽管它会影响空间等。武断的方式和无关的方式不同。
- @乔斯基特:你是说我必须选择一种编码方式,例如,如果我要做的就是把一个string转换成一个byte[],压缩它,然后把它写进一个文件,这样明天我就能把它读到一个byte[],然后在同一台机器上将它解压缩成一个string?如果是这样,我觉得这有点让人震惊——为什么编码很重要?是的,我明天要"解释"字符串,但是编码有什么关系呢?唯一重要的是,我要回到我开始时的状态…就是这样。
- @是的,当然。就像要将图片保存到磁盘上必须选择图像格式一样。尽可能使用这个类比。字符串不是由字节组成的(概念上),因此要转换为字节,必须进行某种类型的转换…这就是编码。
- @琼斯基特:呃……是的,它必须经过一些转换,从定义上来说是正确的。但您不必关心具体的转换是什么,只要一个黑盒可以为您解码字节。正确的?我觉得这很明显…为什么你要关心盒子里有什么(特定的编码)?所以,你不必知道它是如何工作的(或者"编码"这个词的意思是什么!)…你只需要byte[] GetBytes(string)和string GetString(byte[])就可以了!这就是BitConverter所做的,没有编码问题。
- 换言之,如果一个人不想解释字节,他应该完全有可能和合法地不知道(也不需要)编码和要求字符串的"byte[]"表示。这就是我要说的——一个使用BitConverter进行转换(或类似的东西)的答案可以很容易地完成这项工作,而且即使只提到一次"编码"这个词也可以做到这一点——所以说真的,编码不是操作人员必须担心的事情。
- @梅尔达:编码是黑匣子。有很多黑盒可供选择(不同的编码)。您不需要了解任何关于内部的信息——但是您需要从两个方面选择相同的转换。使用BitConverter的答案仍然选择了一种编码——它只是选择不称之为编码。如果我说,"你需要选择一个字符串到字节的转换,通常是通过System.Text.Encoding进行的",你会更愿意吗?这是完全相同的事情,只是在IMO中说得更笨拙。再一次,想想图像格式:你需要选择从像素到字节的格式。
- 重要的一点是,用户不能要求byte[]表示,因为有许多不同的选项可用。
- @jonskeet:"如果我说,"你需要选择一个字符串到字节的转换,通常通过System.Text.Encoding--是吗?准确地说:如果你说过,那么用户就不需要知道Unicode,就可以实现他的目标!这是Text.Encoding和BitConverter之间的关键区别——其中一个是当你真正关心编码时,另一个是当编码与你的目标100%无关时。这就是我在这里评论的原因:你说操作需要知道Unicode,而实际上它是无关的(只使用BitConverter)。
- @梅尔达:使用BitConverter仍然是一个选择,只是没有意识到有选择。(而且,我也找不到你所说的哪种BitConverter方法,老实说。)再想一想图像版本:如果有人问你如何将图片保存到磁盘上,你会问什么格式的自然问题吗?我不明白为什么要有人知道字节和字符之间的基本区别,以及选择不同编码的能力,这是有争议的。他们不必执行它们。
- @乔恩斯基特:噢,抱歉提到BitConverter,我的意思是System.Buffer.BlockCopy,它可以复制任何原始数组(如char[])到byte[],反之亦然…我想的是错误的班级,抱歉把你弄糊涂了。
- @乔斯基特:关于图片任务:这是同一件事。如果BlockCopy可以在Picture类上执行编码/解码,那么如果您永远无法自己解释字节,那么您需要对各种图像格式(甚至它们的存在)一无所知,以便实现所需的内容。不需要告诉用户去了解BMP。相比学习Unicode,跳过(实际上没有)这一步的障碍要小得多!
- 你有一个.NET映像类的例子可以处理Buffer.BlockCopy吗?你不需要知道太多关于Unicode的知识,尽管很明显越多越好。但你需要做出选择。如果你想写一个StringConverter类,它隐藏了这个选择,并且总是使用Encoding.UTF8或其他东西,那么继续吧——但是你仍然在做一个选择,我认为隐藏它对任何人都没有好处。你迟早会遇到这样一种情况,你需要了解编码的基本知识,那为什么不早点学而不迟学呢?
- @Mehrdad通过让黑盒任意决定编码,特别是依赖于UTF-16中字符串的底层.NET表示,可以引入未来潜在的错误。如果.NET系统的下一次更新改变了字符串在内存中的表示方式,该怎么办?例如,它可以是big endian而不是little endian。假设我们按照您的方式将字符串转换为字节数组,然后压缩它。经过几个月和.NET更新后,我们尝试解压缩并转换回字符串。但这次会是垃圾!因为没有明确指定编码。
- @塔纳西奥尼迪斯:已经5年了,但回顾过去,我仍然清楚地表明,您是否应该指定编码取决于您正试图做什么。请注意,这不是"让黑盒决定编码"。BlockCopy没有决定任何编码,这就是问题所在。例如,如果您需要在同一系统上进行无损传输,则无论原始字节是否根据任何特定编码有效,都必须使用它们。如果你需要互操作性,你需要编码/解码。
- @Mehrdad假设首先有原始字节。.NET实现带有基础char数组的字符串,但这是实现细节。即使在相同的系统之间,也没有人保证会有一个底层数组来获取原始字节。它可以很容易地转换成一个链接列表或任何其他数据结构(不太可能,但您仍然明白这一点)。不过,您仍然需要指定一种将该字符串(使用这种奇怪的底层实现)转换为字节序列的方法,这种从字符串转换为字节的方法称为编码。
- @Thanassioannis:首先,C允许您固定一个字符串并直接访问底层字符,所以您是错误的。第二,即使事实并非如此,链表(或其他任何东西)也不会改变任何东西。无论底层实现是什么,您都有Buffer.BlockCopy()和string.ToCharArray,它们为您提供可以用于完美重建的原始字节。他们是否派人去攀登珠穆朗玛峰,用无线电向月球和月球背面传送人物,完全取决于框架,而不是你的业务,完全无关。
- @Thanassionenidis:想象一下,为运行在两台机器上的程序编写一个通信库,可能使用API void Send(string),string Receive()。你真的应该能够像传送char[]或byte[]一样,自己传送string。无论string是UTF-16LE、UTF-16BE还是其他,这都与您的图书馆无关。它可以是你所关心的全部随机代码单元。你的图书馆可以而且必须做它的无损传输工作,不管怎样。假设内部编码不仅是不必要的,而且会丢失信息。
- @对于char数组,在应用某种编码之前,它不是字节数组。BlockCopy在您的情况下进行这种编码,即使这种编码只是复制char数组的每个字节的内存。它不需要是System.Text.Encodings中的一个(为了不丢失信息)。无论您使用什么方法获得字节数组,都是一种编码。关于如何从字符串中获取byte[]的约定。如果您提到的库是在相同的系统或相同的系统中来回转换,则无需指定编码。图书馆为你做这个。
- 但即使使用同一个库,如果它依赖于底层实现,也可能引入bug。您不能保证在解码时系统是相同的。如果.NET在传输的接收部分从小endian变为大endian呢?ToCharArray将以小尾数编码,接收端的FromCharArray将采用大尾数编码,这将导致数据损坏。显然,您的方法是在.NET中将string转换为byte[]。但是,明确指定编码也是将string转换为byte[]的另一种方法,并且看起来更健壮。
- @问题是谁提供什么合同,被呼叫者是否应该关心。但在这一点上,你只是在重复你自己。我没有什么要补充的。继续前进。
您使用的是什么编码?康拉德已经把事情搞砸了,但是还有其他人在那里,你可能会得到错误的结果:
1
| byte[] bytes = System.Text.Encoding.XXX.GetBytes(text) |
其中,XXX可以是:
1 2 3 4 5 6 7
| ASCII
BigEndianUnicode
Default
Unicode
UTF32
UTF7
UTF8 |
这样地:
1 2
| string test ="text";
byte[] arr = Encoding.UTF8.GetBytes(test); |