如何转换string
为byte[]
在.NET(C#),而无需手动指定一个特定的编码?
我将对字符串进行加密。我可以加密而不进行转换,但是我仍然想知道为什么编码在这里起作用。
另外,为什么还要考虑编码?我不能简单地获取字符串存储在哪个字节中?为什么要依赖字符编码?
如何转换string
为byte[]
在.NET(C#),而无需手动指定一个特定的编码?
我将对字符串进行加密。我可以加密而不进行转换,但是我仍然想知道为什么编码在这里起作用。
另外,为什么还要考虑编码?我不能简单地获取字符串存储在哪个字节中?为什么要依赖字符编码?
Answers:
就像您提到的那样,您的目标很简单,就是“获取字符串存储在哪个字节中”。
(并且,当然,能够从字节中重建字符串。)
只需这样做:
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);
}
只要您的程序(或其他程序)不尝试以某种方式解释字节(您显然没有提到您打算这样做),那么这种方法就没有错!无须担心编码,只会使您的生活变得更加复杂。
因为您只是在看bytes,所以它的编码和解码都一样。
但是,如果使用特定的编码,则会给编码/解码无效字符带来麻烦。
GetString
并且GetBytes
需要在系统上使用相同的字节顺序工作执行。因此,您不能使用它来获取要在其他地方转换为字符串的字节。因此,我很难想出一种想要使用它的情况。
例如:
byte[] b1 = System.Text.Encoding.UTF8.GetBytes (myString);
byte[] b2 = System.Text.Encoding.ASCII.GetBytes (myString);
编码为何如此重要的一个小样本:
string pi = "\u03a0";
byte[] ascii = System.Text.Encoding.ASCII.GetBytes (pi);
byte[] utf8 = System.Text.Encoding.UTF8.GetBytes (pi);
Console.WriteLine (ascii.Length); //Will print 1
Console.WriteLine (utf8.Length); //Will print 2
Console.WriteLine (System.Text.Encoding.ASCII.GetString (ascii)); //Will print '?'
ASCII根本无法处理特殊字符。
在内部,.NET框架使用UTF-16表示字符串,因此,如果您只想获取.NET使用的确切字节,请使用System.Text.Encoding.Unicode.GetBytes (...)
。
有关更多信息,请参见.NET Framework(MSDN)中的字符编码。
公认的答案非常非常复杂。为此使用包含的.NET类:
const string data = "A string with international characters: Norwegian: ÆØÅæøå, Chinese: 喂 谢谢";
var bytes = System.Text.Encoding.UTF8.GetBytes(data);
var decoded = System.Text.Encoding.UTF8.GetString(bytes);
如果不需要,不要重新发明轮子。
System.Text.Encoding.Unicode
上讲很好,但是编码应等同于Mehrdad的答案。
System.Text.Encoding.Unicode.GetBytes
可能会更精确。
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());
您需要考虑编码,因为1个字符可以由1个或多个字节(最多约6个字节)表示,并且不同的编码将对这些字节进行不同的处理。
乔尔对此发表了文章:
这是一个受欢迎的问题。重要的是要了解问题作者的要求,并且该要求与最常见的要求有所不同。为了防止在不需要的地方滥用该代码,我已经在后面的第一个回答。
每个字符串都有一个字符集和编码。当您将System.String
对象转换为数组时,System.Byte
您仍然具有字符集和编码。对于大多数用法,您会知道需要哪种字符集和编码,.NET使“转换转换复制”变得很简单。只需选择合适的Encoding
班级即可。
// using System.Text;
Encoding.UTF8.GetBytes(".NET String to byte array")
转换可能需要处理目标字符集或编码不支持源字符的情况。您可以选择:例外,替换或跳过。默认策略是替换“?”。
// using System.Text;
var text = Encoding.ASCII.GetString(Encoding.ASCII.GetBytes("You win €100"));
// -> "You win ?100"
显然,转换并不一定是无损的!
注意:System.String
源字符集为Unicode。
唯一令人困惑的是,.NET使用字符集的名称作为该字符集的一种特定编码的名称。Encoding.Unicode
应该叫Encoding.UTF16
。
多数情况就是这样。如果那是您的需要,请在这里停止阅读。如果您不了解编码是什么,请参阅有趣的Joel Spolsky文章。
现在,问题作者问:“每个字符串都存储为字节数组,对吗?为什么我不能简单地拥有这些字节?”
他不想任何转换。
从C#规范:
C#中的字符和字符串处理使用Unicode编码。char类型表示UTF-16代码单元,而字符串类型表示UTF-16代码单元的序列。
因此,我们知道,如果我们要求空转换(即,从UTF-16到UTF-16),我们将获得所需的结果:
Encoding.Unicode.GetBytes(".NET String to byte array")
但是,为了避免提及编码,我们必须采用另一种方式。如果可以接受中间数据类型,则有一个概念上的捷径:
".NET String to byte array".ToCharArray()
这并不能为我们提供所需的数据类型,但是Mehrdad的答案显示了如何使用BlockCopy将此Char数组转换为Byte数组。但是,这会将字符串复制两次!而且,它也明确使用编码特定的代码:datatype System.Char
。
获取字符串存储的实际字节的唯一方法是使用指针。该fixed
语句允许获取值的地址。根据C#规范:
[对于]字符串类型的表达式,...初始化程序将计算字符串中第一个字符的地址。
为此,编译器使用编写代码跳过字符串对象的其他部分RuntimeHelpers.OffsetToStringData
。因此,要获取原始字节,只需创建一个指向字符串的指针并复制所需的字节数即可。
// using System.Runtime.InteropServices
unsafe byte[] GetRawBytes(String s)
{
if (s == null) return null;
var codeunitCount = s.Length;
/* We know that String is a sequence of UTF-16 codeunits
and such codeunits are 2 bytes */
var byteCount = codeunitCount * 2;
var bytes = new byte[byteCount];
fixed(void* pRaw = s)
{
Marshal.Copy((IntPtr)pRaw, bytes, 0, byteCount);
}
return bytes;
}
正如@CodesInChaos所指出的,结果取决于计算机的字节序。但是问题作者对此并不关心。
Length
[of属性String
]返回Char
此实例中的对象数,而不是Unicode字符数。” 因此,您的示例代码正确无误。
new String(new []{'\uD800', '\u0030'})
Globalization.SortKey
,提取KeyData
,然后将每个字节的结果打包成String
[每个字符两个字节,MSB首先 ],则调用String.CompareOrdinal
结果字符串将比调用或SortKey.Compare
实例快得多。SortKey
甚至调用memcmp
这些实例。鉴于此,我想知道为什么KeyData
返回a Byte[]
而不是a String
?
其他人已经回答了问题的第一部分(如何获取字节):在System.Text.Encoding
名称空间中查找。
我将解决您的后续问题:为什么需要选择编码?为什么不能从字符串类本身中得到它?
答案分为两部分。
首先,字符串类内部使用的字节无关紧要,并且每当您假设它们出现时,就很可能引入错误。
如果您的程序完全位于.Net世界之内,那么即使您正在通过网络发送数据,也不必担心完全为字符串获取字节数组。而是使用.Net序列化来担心传输数据。您不必再担心实际的字节数了:序列化格式化程序会为您完成此操作。
另一方面,如果您无法保证将这些字节发送到某个地方,将会从.Net序列化流中提取数据怎么办?在这种情况下,您确实确实需要担心编码,因为显然此外部系统在乎。同样,字符串使用的内部字节也没关系:您需要选择一种编码,这样就可以在接收端清楚地知道此编码,即使它是.Net内部使用的相同编码也是如此。
我了解在这种情况下,您可能更愿意在可能的情况下使用字符串变量存储在内存中的实际字节,这样可能会节省创建字节流的工作。但是,我告诉您,与确保另一端可以理解您的输出,并确保您的编码必须是明确的相比,这并不重要。此外,如果您确实想匹配内部字节,则只需选择Unicode
编码即可节省性能。
这使我进入第二部分...选择Unicode
编码是告诉.Net使用基础字节。您确实需要选择这种编码,因为当出现一些新的Unicode-Plus时,.Net运行时需要自由使用这种更新更好的编码模型,而不会破坏程序。但是,就目前而言(以及可预见的未来),仅选择Unicode编码即可满足您的需求。
理解必须将字符串重写为电线也很重要,即使使用匹配的编码,这也至少涉及位模式的一些翻译。计算机需要考虑诸如Big vs Little Endian,网络字节顺序,数据包化,会话信息等问题。
只是为了证明Mehrdrad的声音回答的作品,他的做法甚至可以坚持的不成对代理字符(其中许多人对我的回答夷为平地,但每个人都同样有罪的,例如System.Text.Encoding.UTF8.GetBytes
,System.Text.Encoding.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.Encoding.Unicode.GetBytes,它们只会将高替代字符替换为值fffd
每当这个问题出现动静时,我仍在考虑一个序列化程序(无论是来自Microsoft还是来自第三方的组件),即使其中包含不成对的替代字符,该序列化程序也可以保留字符串;我不时在Google上搜索:序列化未配对的代理字符.NET。这不会让我失去任何睡眠,但是每时每刻都有人在烦恼我,我的回答是有缺陷的,但是对于不成对的代理角色,他们的回答同样有缺陷。
哎呀,微软应该System.Buffer.BlockCopy
在它中使用BinaryFormatter
ツ
谢谢!
System.Buffer.BlockCopy
内部使用的序列化库,那么所有倡导编码的人的论据都将是徒劳的
FFFD
该字符出错是有意义的。如果要执行手动字符串操作,建议使用char []。
System.String
是的不可变序列Char
;.NET始终允许String
从任何对象构造对象,Char[]
并将其内容导出到Char[]
包含相同值的,即使原始对象Char[]
包含不成对的替代对象。
试试看,更少的代码:
System.Text.Encoding.UTF8.GetBytes("TEST String");
System.Text.Encoding.UTF8.GetBytes("Árvíztűrő tükörfúrógép);
,然后哭!它的工作,但System.Text.Encoding.UTF8.GetBytes("Árvíztűrő tükörfúrógép").Length != System.Text.Encoding.UTF8.GetBytes("Arvizturo tukorfurogep").Length
同时"Árvíztűrő tükörfúrógép".Length == "Arvizturo tukorfurogep".Length
好吧,我已经阅读了所有答案,它们都是关于使用编码或关于删除未配对代理的序列化的答案。
例如,当字符串来自SQL Server时,这是很糟糕的,SQL Server是从存储例如密码哈希的字节数组构建的。如果我们从中删除任何内容,它将存储一个无效的哈希,并且如果我们要将其存储在XML中,我们希望将其保持不变(因为XML编写器会在发现的任何未配对代理中删除异常)。
因此,在这种情况下,我使用字节数组的Base64编码,但是嘿,在Internet上,C#仅对此提供一种解决方案,并且其中包含错误,并且只是一种方法,因此,我已修复了该错误并将其写回程序。未来的Google员工,您好!
public static byte[] StringToBytes(string str)
{
byte[] data = new byte[str.Length * 2];
for (int i = 0; i < str.Length; ++i)
{
char ch = str[i];
data[i * 2] = (byte)(ch & 0xFF);
data[i * 2 + 1] = (byte)((ch & 0xFF00) >> 8);
}
return data;
}
public static string StringFromBytes(byte[] arr)
{
char[] ch = new char[arr.Length / 2];
for (int i = 0; i < ch.Length; ++i)
{
ch[i] = (char)((int)arr[i * 2] + (((int)arr[i * 2 + 1]) << 8));
}
return new String(ch);
}
Convert.ToBase64String(arr);
了base64转换byte[] (data) <-> string (serialized data to store in XML file)
。但是要获得最初的名称,byte[] (data)
我需要对String
包含二进制数据的对象做一些事情(这是MSSQL将其返回给我的方式)。因此,以上功能适用于String (binary data) <-> byte[] (easy accessible binary data)
。
另外,请说明为什么要考虑编码。我不能简单地获取字符串存储在哪个字节中?为什么要依赖编码?
因为没有“字符串的字节”之类的东西。
字符串(或更笼统地说是文本)由字符组成:字母,数字和其他符号。就这样。但是计算机对字符一无所知。他们只能处理字节。因此,如果要使用计算机存储或传输文本,则需要将字符转换为字节。你是怎样做的?这是编码出现的地方。
编码不过是将逻辑字符转换为物理字节的约定。最简单和最广为人知的编码是ASCII,这是您用英语书写时所需要的。对于其他语言,您将需要更完整的编码,因为任何一种Unicode风格都是当今最安全的选择。
因此,简而言之,尝试“不使用编码即可获取字符串的字节”与“不使用任何语言编写文本”一样不可能。
顺便说一句,我强烈建议您(和其他任何人)阅读这一小知识:每个软件开发人员绝对绝对要完全了解Unicode和字符集(没有任何借口!)
C#将a转换string
为byte
数组:
public static byte[] StrToByteArray(string str)
{
System.Text.UTF8Encoding encoding=new System.Text.UTF8Encoding();
return encoding.GetBytes(str);
}
byte[] strToByteArray(string str)
{
System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
return enc.GetBytes(str);
}
您可以使用以下代码在字符串和字节数组之间进行转换。
string s = "Hello World";
// String to Byte[]
byte[] byte1 = System.Text.Encoding.Default.GetBytes(s);
// OR
byte[] byte2 = System.Text.ASCIIEncoding.Default.GetBytes(s);
// Byte[] to string
string str = System.Text.Encoding.UTF8.GetString(byte1);
随着Span<T>
C#7.2 的发布,将字符串的基础内存表示捕获到托管字节数组中的规范技术为:
byte[] bytes = "rubbish_\u9999_string".AsSpan().AsBytes().ToArray();
将其转换回去应该是一个入门级的工作,因为这实际上意味着您正在以某种方式解释数据,但出于完整性考虑:
string s;
unsafe
{
fixed (char* f = &bytes.AsSpan().NonPortableCast<byte, char>().DangerousGetPinnableReference())
{
s = new string(f);
}
}
名称NonPortableCast
和DangerousGetPinnableReference
应该进一步说明您可能不应该这样做。
请注意,使用该工具Span<T>
需要安装System.Memory NuGet软件包。
无论如何,实际的原始问题和后续注释都暗示未对“底层内存”进行“解释”(我认为这意味着未对它们进行修改或超出了按原样编写它的需要),表明Stream
该类已实现某些实现应该完全代替将数据作为字符串进行推理。
我不确定,但是我认为该字符串将其信息存储为Chars数组,该数组的字节效率很低。具体地说,Char的定义是“代表Unicode字符”。
以以下示例为例:
String str = "asdf éß";
String str2 = "asdf gh";
EncodingInfo[] info = Encoding.GetEncodings();
foreach (EncodingInfo enc in info)
{
System.Console.WriteLine(enc.Name + " - "
+ enc.GetEncoding().GetByteCount(str)
+ enc.GetEncoding().GetByteCount(str2));
}
请注意,在两种情况下,Unicode答案均为14个字节,而第一个的UTF-8答案仅为9个字节,而第二个则仅为7个字节。
因此,如果只希望字符串使用字节,则只需使用Encoding.Unicode
,但存储空间效率低下。
关键问题是字符串中的字形需要32位(对于字符代码为16位),而一个字节只有8位备用。除非您将自己限制为仅包含ASCII字符的字符串,否则不存在一对一映射。System.Text.Encoding有很多将字符串映射到byte []的方法,您需要选择一种避免信息丢失的方法,当客户端需要将byte []映射回字符串时,该方法易于使用。 。
Utf8是一种流行的编码,它紧凑且无损。
最快的方法
public static byte[] GetBytes(string text)
{
return System.Text.ASCIIEncoding.UTF8.GetBytes(text);
}
编辑 诚诚评论这是最好的方法:
Encoding.UTF8.GetBytes(text)
在不手动指定特定编码的情况下,如何在.NET(C#)中将字符串转换为byte []?
.NET中的字符串将文本表示为一系列UTF-16代码单元,因此这些字节已经在UTF-16的内存中进行了编码。
梅尔达德的答案
您可以使用Mehrdad的answer,但实际上使用的是编码,因为chars是UTF-16。它调用ToCharArray,后者查看源代码创建一个char[]
,并将内存直接复制到它。然后它将数据复制到也分配的字节数组中。因此,在幕后它将复制基础字节两次,并分配一个在调用后未使用的char数组。
汤姆·布洛杰特的答案
Tom Blodget的答案比Mehrdad快20-30%,因为它跳过了分配char数组并将字节复制到其中的中间步骤,但它要求您使用该/unsafe
选项进行编译。如果您绝对不想使用编码,我认为这是要走的路。如果将加密登录名放在fixed
块中,则甚至不需要分配单独的字节数组并将字节复制到该数组中。
另外,为什么还要考虑编码?我不能简单地获取字符串存储在哪个字节中?为什么要依赖字符编码?
因为那是正确的方法。 string
是一个抽象。
如果您有带有无效字符的“字符串”,那么使用编码可能会给您带来麻烦,但这不应该发生。如果您要使用无效字符将数据输入字符串,则说明这样做是错误的。首先,您可能应该使用字节数组或Base64编码。
如果使用System.Text.Encoding.Unicode
,您的代码将更具弹性。您不必担心代码将在其上运行的系统的字节顺序。您无需担心下一个版本的CLR是否使用其他内部字符编码。
我认为问题不是您为什么要担心编码,而是为什么要忽略它并使用其他东西。编码旨在表示字节序列中字符串的抽象。 System.Text.Encoding.Unicode
将为您提供一点字节序的字节序编码,并且无论现在还是将来,都将在每个系统上执行相同的操作。
与OP问题最接近的方法是Tom Blodget的方法,它实际上是进入对象并提取字节的。我说最接近是因为它取决于String对象的实现。
"Can't I simply get what bytes the string has been stored in?"
当然,但这就是问题的根本错误所在。字符串是一个可能具有有趣数据结构的对象。我们已经知道了,因为它允许存储未配对的代理。它可能会存储长度。它可以保持指向每个“配对”代理的指针,从而可以快速计数。等等所有这些额外的字节都不是字符数据的一部分。
您想要的是数组中每个字符的字节。这就是“编码”的来源。默认情况下,您将获得UTF-16LE。如果除了往返行程外,您不关心字节本身,则可以选择包括“默认”在内的任何编码,然后稍后再转换回去(假设使用相同的参数,例如默认编码是什么,代码点,错误修复,允许的东西,例如不成对的代理人等。
但是,为什么要把“编码”交给魔术呢?为什么不指定编码,以使您知道要获取的字节?
"Why is there a dependency on character encodings?"
编码(在这种情况下)仅表示代表您的字符串的字节。不是字符串对象的字节。您想要将字符串存储在其中的字节-这是天真的问题所在。您需要连续数组中代表字符串的字符串字节,而不是字符串对象可能包含的所有其他二进制数据。
这意味着字符串的存储方式无关紧要。您希望将一个“编码”字符串转换为字节数组中的字节。
我喜欢Tom Bloget的答案,因为他将您带向了“字符串对象的字节”方向。但是,它依赖于实现,并且因为他正在查看内部结构,所以可能很难重新构造字符串的副本。
Mehrdad的回答是错误的,因为它在概念层面上具有误导性。您仍然有一个已编码的字节列表。他的特定解决方案允许保留未配对的代理-这取决于实现。如果GetBytes
默认情况下以UTF-8返回字符串,则他的特定解决方案将无法准确产生字符串的字节。
我已经改变了主意(Mehrdad的解决方案)-这不是得到字符串的字节;而是获取从字符串创建的字符数组的字节。不管编码如何,c#中的char数据类型都是固定大小。这样可以产生长度一致的字节数组,并允许根据字节数组的大小来复制字符数组。因此,如果编码为UTF-8,但每个字符为6个字节以容纳最大的utf8值,它将仍然有效。所以确实-字符的编码无关紧要。
但是使用了转换-每个字符都放入一个固定大小的框(C#的字符类型)中。但是,该表示形式无关紧要,从技术上讲,这是OP的答案。所以-如果您仍要进行转换...为什么不“编码”?
&。(Char) 55906
(Char) 55655
因此,您可能是错的,Mehrdad的答案是安全的转换,无需考虑使用哪种编码类型。
您可以使用下面的代码转换string
为byte array
在.NET
string s_unicode = "abcéabc";
byte[] utf8Bytes = System.Text.Encoding.UTF8.GetBytes(s_unicode);
如果您确实想要一个字符串的基础字节的副本,则可以使用下面的函数。但是,您不应该继续阅读以找出原因。
[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()
这很可能会产生相同的结果,更易于键入,并且字节始终会与调用进行往返
System.Text.Encoding.Unicode.GetString()
这里是我的不安全落实String
到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,此方法还可以用作String扩展:
public static unsafe class StringExtensions
{
public static Byte[] ToByteArray(this String s)
{
// Method Code
}
}
RuntimeHelpers.OffsetToStringData
.NET的Itanium版本是否为8的倍数?因为否则将由于未对齐的读取而失败。
memcpy
?stackoverflow.com/a/27124232/659190
只需使用以下命令:
byte[] myByte= System.Text.ASCIIEncoding.Default.GetBytes(myString);
System.Text.ASCIIEncoding.Default.GetBytes("Árvíztűrő tükörfúrógép.").ToString();
将返回"Árvizturo tukörfurogép."
无法检索的丢失信息。(而且我还没有提到您会丢失所有字符的亚洲语言。)
由于以下事实,可以用几种不同的方式将字符串转换为字节数组:.NET支持Unicode,并且Unicode标准化了几种不同的编码,称为UTF。它们具有不同的字节表示长度,但在某种意义上是等效的,即在对字符串进行编码时,可以将其编码回字符串,但是如果可以使用一个UTF对字符串进行编码并在假定使用不同UTF的情况下对其进行解码,则可以拧紧起来
此外,.NET支持非Unicode编码,但在通常情况下无效(仅在实际字符串(例如ASCII)中使用Unicode代码点的有限子集时才有效)。在内部,.NET支持UTF-16,但是对于流表示,通常使用UTF-8。它也是Internet的标准事实。
毫不奇怪,类System.Text.Encoding
是抽象类,支持将字符串序列化为字节数组并反序列化。其派生类支持具体的编码:ASCIIEncoding
和四个System.Text.UnicodeEncoding
UTF (支持UTF-16)
引用此链接。
用于使用序列化为字节数组System.Text.Encoding.GetBytes
。对于逆运算,请使用System.Text.Encoding.GetChars
。此函数返回一个字符数组,因此要获取字符串,请使用字符串构造函数System.String(char[])
。
引用此页。
例:
string myString = //... some string
System.Text.Encoding encoding = System.Text.Encoding.UTF8; //or some other, but prefer some UTF is Unicode is used
byte[] bytes = encoding.GetBytes(myString);
//next lines are written in response to a follow-up questions:
myString = new string(encoding.GetChars(bytes));
byte[] bytes = encoding.GetBytes(myString);
myString = new string(encoding.GetChars(bytes));
byte[] bytes = encoding.GetBytes(myString);
//how many times shall I repeat it to show there is a round-trip? :-)
正如Tyler恰当地说的那样,这是因为“字符串不是纯数据。它们还具有信息。” 在这种情况下,该信息是创建字符串时假定的编码。
这是基于OP对他自己的问题的评论,如果我理解OP关于用例的提示,这是正确的问题。
由于上述假定的编码,将二进制数据存储在字符串中可能是错误的方法!无论哪种程序或库将二进制数据存储在一个string
(而不是一个byte[]
更合适的数组中),在开始之前就已经失败了。如果他们通过REST请求/响应或必须传输字符串的任何内容向您发送字节,Base64将是正确的方法。
其他人都错误地回答了这个错误的问题。
如果字符串按原样看起来不错,则只需选择一种编码(最好是一种以UTF开头的编码),然后使用相应的System.Text.Encoding.???.GetBytes()
函数,然后告诉谁将字节提供给您选择的编码。
当被问及您打算如何处理这些字节时,您回答:
我要加密它。我可以加密而不进行转换,但是我仍然想知道为什么编码在这里起作用。只要给我字节就是我所说的。
无论您打算通过网络发送此加密数据,稍后再将其加载回内存还是将其蒸腾到另一个进程,您显然都打算在某个时候对其进行解密。在这种情况下,答案是您正在定义通信协议。不应根据您的编程语言及其关联的运行时的实现细节来定义通信协议。有几个原因:
为了进行通信(使用完全不同的过程或将来使用相同的程序进行通信),您需要严格定义协议,以最大程度地减少使用它或意外创建错误的难度。依赖.NET的内部表示形式不是严格,清晰的甚至保证是一致的定义。标准编码是严格的定义,将来不会令您失望。
换句话说,如果不指定编码,就无法满足一致性要求。
如果发现由于.NET内部使用它或出于任何其他原因而使您的进程性能显着提高,则可以肯定选择直接使用UTF-16,但是您需要显式选择该编码并在代码中显式执行这些转换,而不是依赖于在.NET的内部实现中。
因此,选择一种编码并使用它:
using System.Text;
// ...
Encoding.Unicode.GetBytes("abc"); # UTF-16 little endian
Encoding.UTF8.GetBytes("abc")
如您所见,实际上,仅使用内置的编码对象比实现自己的读取器/写入器方法要少。
两种方式:
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();
}
和,
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;
}
我倾向于使用底部比顶部更多的频率,而没有为它们设定速度基准。
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