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

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

此外,为什么还要考虑编码?我不能简单地获取字符串存储的字节数吗?为什么依赖字符编码?


当前回答

如果您真的想要一个字符串的基本字节的副本,可以使用下面这样的函数。然而,你不应该继续阅读以找出原因。

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

其他回答

LINQ的简单代码

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

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

但您仍然可以使用它来理解LINQ,并使用更合适的编码:

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

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

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

毫不奇怪,System.Text.Encoding类是一个抽象类,它支持将字符串序列化为字节数组和反序列化;它的派生类支持具体编码:ASCIIEncoding和四个UTF(System.Text.UnicodeEncoding支持UTF-16)

参考此链接。

对于使用System.Text.Encoding.GetBytes对字节数组进行序列化。对于反向操作,使用System.Text.Encoding.GGetChars。此函数返回字符数组,因此要获取字符串,请使用字符串构造函数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? :-)

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

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

计算机只理解原始二进制数据,原始比特。一位是二进制数字:0或1。8位数字是一个字节。一个字节是介于0和255之间的数字。

ASCII是一种将数字转换为字符的表格。0到31之间的数字是控件:制表符、换行符和其他。32到126之间的数字为可打印字符:字母a,数字1,%符号,下划线_

因此,对于ASCII,有33个控制字符和95个可打印字符。

ASCII是当今最常用的字符编码。Unicode表的第一个条目是ASCII,并与ASCII字符集匹配。

ASCII是一个7位字符集。介于0和127之间的数字。使用8位,我们可以达到255位。

ASCII最常见的替代品是EBCDIC,它与ASCII不兼容,今天仍然存在于IBM计算机和数据库中。

1字节,因此8位数字是当今计算机科学中最常用的单位。1字节是介于0和255之间的数字。

ASCII为0到127之间的每个数字定义了一个含义。

与128和255之间的数字相关联的字符取决于所使用的字符编码。目前广泛使用的两种字符编码是windows1252和UTF-8。

在windows1252中,欧元符号对应的数字是128。1字节:[A0]。在Unicode数据库中,欧元符号是数字8364。

现在我给你电话8364。两个字节:[20,AC]。在UTF-8中,欧元符号是数字14844588。三个字节:[E282AC]。

现在我给你一些原始数据。假设20AC。是两个windows1252字符:£还是一个Unicode€符号?

我给你一些原始数据。e282交流。82是windows1252中未分配的字符,因此它可能不是windows1252。它可能是macRoman“”C“”或OEM 437“”或UTF-8“€”符号。

根据字符编码的特性和统计数据,可以猜测原始字节流的编码,但没有可靠的方法。128到255之间的数字在UTF-8中是无效的。é在某些语言(法语)中很常见,因此如果您看到许多字节的值E9被字母包围,那么它可能是一个windows1252编码字符串,E9字节表示é字符。

当您有一个表示字符串的原始字节流时,了解匹配的编码比猜测要好得多。

下面是曾经被广泛使用的各种编码中的一个原始字节的屏幕截图。