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

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

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


当前回答

要将字符串转换为字节[],请使用以下解决方案:

string s = "abcdefghijklmnopqrstuvwxyz";
byte[] b = System.Text.UTF32Encoding.GetBytes(s);

我希望这有帮助。

其他回答

OP的问题:“如何在.NET(C#)中将字符串转换为字节数组?”

您可以使用以下代码:

static byte[] ConvertString (string s) {
    return new byte[0];
}

作为一个好处,编码无关紧要!哦,等等,这是一个ecoding。。。它只是微不足道的,而且损耗很大。

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

我将回答您的后续问题:为什么需要选择编码?为什么不能从字符串类本身获得这些信息?

答案分为两部分。

首先,字符串类内部使用的字节并不重要,只要假设它们存在,就可能引入错误。

如果您的程序完全在.Net世界中,那么您根本不需要担心获取字符串的字节数组,即使您正在通过网络发送数据。相反,请使用.Net Serialization来担心数据传输问题。您不再担心实际的字节数:Serialization格式化程序会为您提供。

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

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

这让我进入第二部分。。。选择Unicode编码就是告诉.Net使用底层字节。您确实需要选择这种编码,因为当一些新的Unicode Plus问世时,.Net运行时需要自由使用这种更新、更好的编码模型,而不会破坏您的程序。但是,目前(以及可预见的未来),只要选择Unicode编码就可以满足您的需要。

理解字符串必须重写为线也是很重要的,即使使用匹配的编码,也至少需要对位模式进行一些转换。计算机需要考虑诸如Big vs Little Endian、网络字节顺序、分组化、会话信息等。

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

Utf8是一种流行的编码方式,它紧凑而无损耗。

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

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

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