IT-Swarm.Net

如何在不手动指定编码的情况下在C#中获得字符串的一致字节表示?

如何在不手动指定特定编码的情况下将string转换为.NET(C#)中的byte[]

我要加密字符串。我可以在不转换的情况下加密它,但我仍然想知道为什么编码在这里发挥作用。

另外,为什么要考虑编码?我不能简单地得到字符串存储的字节数吗?为什么依赖于字符编码?

2055
Agnel Kurian

与此处的答案相反,您不需要担心编码 if 字节不需要解释!

就像你提到的那样,你的目标就是 “获取字符串存储在字节中的字节数”
(当然,能够从字节中重新构造字符串。)

对于这些目标,我老实说 not 理解为什么人们一直告诉你需要编码。你当然不需要担心编码。

只需这样做:

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);
}

只要你的程序(或其他程序)没有尝试 解释 某些字节,你显然没有提到你打算这样做,那么这种方法有 没什么 错了!担心编码只会让你的生活更加复杂,没有真正的理由。

这种方法的其他好处:

如果字符串包含无效字符并不重要,因为您仍然可以获取数据并重建原始字符串!

它将被编码和解码相同,因为你是 只看字节

但是,如果您使用了特定的编码,那么编码/解码无效字符会给您带来麻烦。

1793
Mehrdad

它取决于你的字符串的编码( _ ascii _UTF-8 ,...)。

例如:

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)。

1079
bmotmans

接受的答案非常非常复杂。使用包含的.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);

如果你不需要,不要重新发明轮子......

267
Erik A. Brandstadmoen
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());
110
Michael Buen

您需要考虑编码,因为1个字符可以用1 或更多 字节(最多约6)表示,不同的编码将以不同的方式处理这些字节。

乔尔有一个帖子:

绝对最低每个软件开发人员绝对必须知道Unicode和字符集(没有借口!)

87
Zhaph - Ben Duguid

这是一个很受欢迎的问题。重要的是要理解作者提出的问题,并且它与最常见的需求不同。为了阻止在不需要的地方滥用代码,我先回答了后面的问题。

共同需要

每个字符串都有一个字符集和编码。将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#spec

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数组。但是,这会复制字符串两次!而且,它也明确使用特定于编码的代码:数据类型System.Char

获取存储String的实际字节的唯一方法是使用指针。 fixed语句允许获取值的地址。来自C#规范:

[For] string类型的表达式,...初始化程序计算字符串中第一个字符的地址。

为此,编译器使用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指出的那样,结果取决于机器的字节顺序。但问题的作者并不关心这一点。

84
Tom Blodget

只是为了证明Mehrdrad的声音 答案 有效,他的方法甚至可以坚持 不成对的代理人物 (其中许多人反对我的答案,但每个人都同样有罪,例如System.Text.Encoding.UTF8.GetBytesSystem.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还是来自第三方组件),它可以持久化字符串,即使它包含不成对的代理字符;我不时地谷歌这个: 序列化不成对的代理人字符.NET 。这并没有让我失去任何睡眠,但是当有人评论我的答案是否存在缺陷时,它会有点烦人,但是当涉及到不成对的代理角色时,他们的答案同样存在缺陷。

Darn,微软应该在其BinaryFormatterツ中使用System.Buffer.BlockCopy

谢谢!

43
Michael Buen

您的问题的第一部分(如何获取字节)已被其他人回答:查看System.Text.Encoding命名空间。

我将解决您的后续问题:为什么需要选择编码?为什么你不能从字符串类本身那里得到它?

答案分为两部分。

首先,字符串类无关紧要内部使用的字节,并且只要你认为它们可能会引入错误。

如果您的程序完全在.Net世界中,那么即使您通过网络发送数据,也不必担心为字符串获取字节数组。相反,使用.Net Serialization来担心传输数据。您不再担心实际的字节:序列化格式化程序会为您执行此操作。

另一方面,如果您将这些字节发送到您无法保证的某个位置会从.Net序列化流中提取数据怎么办?在这种情况下,你肯定需要担心编码,因为显然这个外部系统在乎。同样,字符串使用的内部字节无关紧要:您需要选择一个编码,以便您可以在接收端明确表示此编码,即使它与.Net内部使用的编码相同。

我知道在这种情况下你可能更喜欢在可能的情况下使用字符串变量存储在字节变量中的实际字节,并且可能会节省一些创建字节流的工作。但是,我把它告诉你,与确保你的输出在另一端被理解相比,并且保证你必须明确你的编码是不重要的。此外,如果您真的想要匹配内部字节,您可以只选择Unicode编码,并节省性能。

这让我想到了第二部分......选择Unicode encoding is 告诉.Net使用底层字节。你确实需要选择这种编码,因为当出现一些新奇的Unicode-Plus时,.Net运行时需要免费使用这种更新,更好的编码模型而不会破坏你的程序。但是,目前(以及可预见的未来),只需选择Unicode编码即可获得所需内容。

理解你的字符串必须重写为连线也很重要,这至少涉及位模式的{即使你使用匹配的编码的一些翻译。计算机需要考虑Big vs Little Endian,网络字节顺序,打包,会话信息等。

42
Joel Coehoorn

试试这个,少了很多代码:

System.Text.Encoding.UTF8.GetBytes("TEST String");
38
Nathan

好吧,我已经阅读了所有的答案,他们是关于使用编码或一个关于序列化,删除不成对的代理人。

例如,字符串来自 SQL Server 它是从存储密码哈希的字节数组构建的,这很糟糕。如果我们从中删除任何东西,它将存储一个无效的哈希,如果我们想将它存储在XML中,我们希望保持原样(因为XML编写器在它找到的任何未配对的代理上删除了一个例外)。

所以我在这种情况下使用 Base64 字节数组编码,但是嘿,在互联网上只有一个解决方案,在C#中,它有bug,只有一种方式,所以我修复了错误和写回程序。在这里,未来的googlers:

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);
}
24
Gman

还请解释为什么要考虑编码。我不能简单地得到字符串存储的字节数吗?为什么这种依赖编码?!!!

因为没有“字符串的字节”之类的东西。

字符串(或更一般地说,文本)由字符组成:字母,数字和其他符号。就这样。然而,计算机对字符一无所知;他们只能处理字节。因此,如果要使用计算机存储或传输文本,则需要将字符转换为字节。你是怎样做的?这是编码到达现场的地方。

编码只不过是将逻辑字符转换为物理字节的惯例。最简单和最知名的编码是ASCII,如果你用英文写作,它就是你所需要的。对于其他语言,您将需要更完整的编码,任何Unicode风格都是当今最安全的选择。

因此,简而言之,尝试“在不使用编码的情况下获取字符串的字节数”与“不使用任何语言编写文本”一样不可能。

顺便说一句,我强烈建议你(以及任何人)阅读这一小段知识: 绝对最低每个软件开发人员绝对必须知道Unicode和字符集(没有借口!)

21
Konamiman

C#将string转换为byte数组:

public static byte[] StrToByteArray(string str)
{
   System.Text.UTF8Encoding  encoding=new System.Text.UTF8Encoding();
   return encoding.GetBytes(str);
}
20
Shyam sundar shah

您可以使用以下代码进行字符串和字节数组之间的转换。

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);
16
Jarvis Stark
byte[] strToByteArray(string str)
{
    System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
    return enc.GetBytes(str);
}
15
gkrogers

我不确定,但我认为字符串将其信息存储为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,但是存储空间效率低下。

12
Ed Marty

随着C#7.2发布的 Span<T> 的出现,将字符串的底层内存表示捕获到托管字节数组的规范技术是:

byte[] bytes = "rubbish_\u9999_string".AsSpan().AsBytes().ToArray();

将其转换回来应该是非首发的,因为这意味着您实际上是以某种方式解释数据,但为了完整起见:

string s;
unsafe
{
    fixed (char* f = &bytes.AsSpan().NonPortableCast<byte, char>().DangerousGetPinnableReference())
    {
        s = new string(f);
    }
}

名称NonPortableCastDangerousGetPinnableReference应该进一步证明你可能不应该这样做。

请注意,使用Span<T>需要安装 System.Memory NuGet包

无论如何, actual original问题和后续注释意味着底层内存没有被“解释”(我假设它不会被修改或读取超出需要按原样写入),表明应该使用Stream类的一些实现,而不是根据字符串推断数据。

11
John Rasch

关键问题是字符串中的字形占用32位(字符代码为16位),但一个字节只有8位备用。除非您将自己限制为仅包含ASCII个字符的字符串,否则不存在一对一映射。 System.Text.Encoding有很多方法可以将字符串映射到byte [],你需要选择一个避免信息丢失的方法,当你需要将byte []映射回字符串时,客户端很容易使用它。

Utf8是一种流行的编码,它紧凑而且没有损耗。

10
Hans Passant

使用:

    string text = "string";
    byte[] array = System.Text.Encoding.UTF8.GetBytes(text);

结果是:

[0] = 115
[1] = 116
[2] = 114
[3] = 105
[4] = 110
[5] = 103
8
mashet

如何在不手动指定特定编码的情况下将字符串转换为.NET(C#)中的byte []?

A string 在.NET中将文本表示为UTF-16代码单元的序列,因此字节在UTF-16中已经在内存中编码。

Mehrdad的回答

您可以使用 Mehrdad的答案 ,但它确实使用编码,因为字符是UTF-16。它调用ToCharArray,它查看 创建char[]并直接将内存复制到它。然后它将数据复制到也分配的字节数组。因此,它会复制底层字节两次并分配一个在调用后未使用的char数组。

Tom Blodget的回答

Tom Blodget的回答 比Mehrdad快20-30%,因为它跳过了分配char数组并将字节复制到它的中间步骤,但它需要你用/unsafe选项进行编译。如果你绝对不想使用编码,我认为这是要走的路。如果将加密登录放在fixed块中,则甚至不需要分配单独的字节数组并将字节复制到其中。

另外,为什么要考虑编码?我不能简单地得到字符串存储的字节数吗?为什么依赖于字符编码?

因为这是正确的方法。 string是一个抽象。

如果您的“字符串”包含无效字符,则使用编码可能会给您带来麻烦,但这不应该发生。如果您使用无效字符将数据输入到字符串中,那么您做错了。您可能应该使用字节数组或Base64编码开始。

如果您使用System.Text.Encoding.Unicode,您的代码将更具弹性。您不必担心代码将运行的系统的 endianness 。如果下一版本的CLR将使用不同的内部字符编码,则无需担心。

我认为问题不在于你为什么要担心编码,而是为什么要忽略它并使用别的东西。编码旨在表示字节序列中字符串的抽象。 System.Text.Encoding.Unicode将为您提供一个小端字节顺序编码,并将在现在和将来的每个系统上执行相同的操作。

8
Jason Goemaat

最快的方式

public static byte[] GetBytes(string text)
{
    return System.Text.ASCIIEncoding.UTF8.GetBytes(text);
}

_ edit _ 作为Makotosan评论说这是现在最好的方法:

Encoding.UTF8.GetBytes(text)
8
Sunrising

最接近OP问题的方法是Tom Blodget,它实际上是进入对象并提取字节。我说最接近因为它取决于String对象的实现。

"Can't I simply get what bytes the string has been stored in?"

当然,但这就是问题中出现根本错误的地方。 String是一个可能具有有趣数据结构的对象。我们已经知道它确实存在,因为它允许存储未配对的代理。它可能存储长度。它可能会指向每个“配对”代理,以便快速计数。等等。所有这些额外字节都不是字符数据的一部分。

你想要的是数组中每个字符的字节。这就是'编码'的用武之地。默认情况下,你会得到UTF-16LE。如果您不关心除了往返之外的字节本身,那么您可以选择任何编码,包括'default',并稍后将其转换回来(假设相同的参数,例如默认编码,代码点,错误修复) ,允许的事情,如未成对的代理人等。

但为什么要让'编码'达到魔法?为什么不指定编码,以便您知道要获得的字节数?

"Why is there a dependency on character encodings?"

编码(在此上下文中)仅表示表示字符串的字节。不是字符串对象的字节。你想要存储字符串的字节 - 这就是问题被天真地问的地方。您希望字符串的字节在表示字符串的连续数组中,而不是字符串对象可能包含的所有其他二进制数据。

这意味着如何存储字符串是无关紧要的。您希望在字节数组中将字符串“Encoded”转换为字节。

我喜欢Tom Bloget的答案,因为他带你走向'字符串对象的'字节'方向。虽然它依赖于实现,并且因为他正在窥视内部,所以可能很难重新构建字符串的副本。

Mehrdad的回答是错误的,因为它在概念层面上具有误导性。您仍然有一个编码的字节列表。他的特殊解决方案允许保留未配对的代理 - 这取决于实现。如果GetBytes默认返回UTF-8中的字符串,那么他的特定解决方案不会准确生成字符串的字节。


我已经改变了主意(Mehrdad的解决方案) - 这不是获取字符串的字节;而是获取从字符串创建的字符数组的字节。无论编码如何,c#中的char数据类型都是固定大小。这允许产生一致的长度字节数组,并且它允许基于字节数组的大小来再现字符数组。因此,如果编码是UTF-8,但每个char是6个字节以容纳最大的utf8值,它仍然可以工作。确实如此 - 角色的编码并不重要。

但是使用了转换 - 每个字符都放在一个固定大小的框中(c#的字符类型)。然而,这种表示无关紧要,这在技术上是OP的答案。所以 - 无论如何你要转换......为什么不'编码'?

6
Gerard ONeill

您可以使用以下代码将string转换为.NET中的byte array

string s_unicode = "abcéabc";
byte[] utf8Bytes = System.Text.Encoding.UTF8.GetBytes(s_unicode);
6
Shyam sundar shah

这是我对StringByte[]转换的不安全实现:

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
    }
}
4
Tommaso Belluzzo

如果你真的想要一个字符串的底层字节的副本,你可以使用如下所示的函数。 但是,你不应该 请继续阅读以找出原因。

[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()
3
Jodrell

只需使用:

byte[] myByte= System.Text.ASCIIEncoding.Default.GetBytes(myString);
3
alireza amini

由于以下事实,字符串可以以几种不同的方式转换为字节数组:.NET支持Unicode,Unicode标准化了几种称为UTF的差异编码。它们具有不同长度的字节表示,但在这种意义上是等效的,当字符串被编码时,它可以被编码回字符串,但是如果字符串用一个UTF编码并且在假设不同的UTF下解码则可以拧紧起来。

此外,.NET支持非Unicode编码,但它们在一般情况下无效(仅当在实际字符串中使用有限的Unicode代码点子集时才有效,例如ASCII)。在.NET内部,.NET支持UTF-16,但对于流表示,通常使用UTF-8。它也是互联网的标准事实。

毫不奇怪,类System.Text.Encoding支持将字符串序列化为字节数组和反序列化,这是一个抽象类;其派生类支持具体编码:ASCIIEncoding和四个UTF(System.Text.UnicodeEncoding支持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? :-)
2
Vijay Singh Rana

这取决于你想要的字节FOR

这是因为,正如Tyler所说 - ,“字符串不是纯数据。它们也有 信息 。”在这种情况下,信息是在创建字符串时假定的编码。

假设您将二进制数据(而不是文本)存储在字符串中

这是基于OP对自己问题的评论,如果我理解OP对用例的暗示,这是正确的问题。

由于上面提到的假定编码,在字符串中存储二进制数据可能是错误的方法!无论在string(而不是更合适的byte[]数组)中存储二进制数据的程序或库,它已经在战斗开始之前就已经失败了。如果他们在REST请求/响应中发送字节给你,或者 必须 传输字符串, Base64 将是正确的方法。

如果您的文本字符串包含未知编码

其他人都错误地回答了这个错误的问题。

如果字符串看起来很好,只需选择一个编码(最好是一个以UTF开头的编码),使用相应的System.Text.Encoding.???.GetBytes()函数,并告诉你给哪些字节你选择的编码。

2
NH.

使用LINQ的简单代码

string s = "abc"
byte[] b = s.Select(e => (byte)e).ToArray();

编辑:如下所述,这不是一个好方法。

但您仍然可以使用它来更好地理解LINQ:

string s = "abc"
byte[] b = s.Cast<byte>().ToArray();
2
Avlin

两种方式:

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;
}

我倾向于使用底部比顶部更频繁,没有为速度进行基准测试。

2
harmonik
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
2
user1120193

字符既是字体表中的查找键,也是排序,大小写版本等词汇传统。

因此,字符不是字节(8位),字节不是字符。特别是,一个字节的256个排列不能容纳某些书面语言中的数千个符号,更不用说所有语言。因此,已经设计了各种用于编码字符的方法。有些编码用于特定类别的语言(ASCII编码);使用代码页的多种语言(扩展ASCII);或者,雄心勃勃地,通过有选择地包括所需的附加字节,Unicode,所有语言。

在诸如.NET框架的系统内,String意味着特定的字符编码。在.NET中,此编码是Unicode。由于框架默认读取和写入Unicode,因此在.NET中通常不需要处理字符编码。

但是,通常,要从字节流中将字符串加载到系统中,您需要知道源编码,以便解释并随后正确转换它(否则代码将被视为已经在系统的默认编码中,因此呈现胡言乱语)。类似地,当字符串写入外部源时,它将以特定编码写入。

0
George

byte[]string

        return BitConverter.ToString(bytes);
0
Piero Alberto

我编写了一个类似于接受的答案的Visual Basic扩展,但直接使用.NET内存和编组进行转换,它支持其他方法不支持的字符范围,如UnicodeEncoding.UTF8.GetStringUnicodeEncoding.UTF32.GetString甚至MemoryStream and BinaryFormatter(无效字符如:????ChrW(55906)ChrW(55655)):

<Extension> _
Public Function ToBytesMarshal(ByRef str As String) As Byte()
    Dim gch As GCHandle = GCHandle.Alloc(str, GCHandleType.Pinned)
    Dim handle As IntPtr = gch.AddrOfPinnedObject
    ToBytesMarshal = New Byte(str.Length * 2 - 1) {}
    Try
        For i As Integer = 0 To ToBytesMarshal.Length - 1
            ToBytesMarshal.SetValue(Marshal.ReadByte(IntPtr.Add(handle, i)), i)
        Next
    Finally
        gch.Free()
    End Try
End Function

<Extension> _
Public Function ToStringMarshal(ByRef arr As Byte()) As String
    Dim gch As GCHandle = GCHandle.Alloc(arr, GCHandleType.Pinned)
    Try
        ToStringMarshal = Marshal.PtrToStringAuto(gch.AddrOfPinnedObject)
    Finally
        gch.Free()
    End Try
End Function
0
Mojtaba Rezaeian