将字符串转换为字节数组和将字节数组转换为字符串

3
将字符串转换为字节数组,然后再转换回来有时会得不到相同的字符串:
RandomNumberGenerator gen = new RNGCryptoServiceProvider();
byte[] randomBytes = new byte[32];
gen.GetBytes(randomBytes);

在某些情况下(或任何编码方式,而不是Unicode):
randomBytes != Encoding.Unicode.GetBytes(Encoding.Unicode.GetString(randomBytes));

我想知道如何执行这个方法,并且肯定会得到相同的结果。非常感谢。


2
你真的在使用!=来比较字节数组吗? - Kirk Woll
2个回答

2

也许你需要的不是文本编码,而是序列化格式。文本编码适用于文本。你正在处理的字节是随机字节。

Base64(Convert.ToBase64String)是否适合你?

你也可以将字节插入字符中(new string(myBytes.Select(b => (char)b).ToArray()))。这将产生不可读的字符串,容易被其他系统损坏。这可能不是正确的方法。


Convert.ToBase64String 返回一个字符串。我需要将该字符串转换为 byte[],然后再转回来。我正在使用 NetworkStream 类来传输字符串,它需要一个 byte[]。 - ido talker
@idotalker 为什么要使用字符串?你有字节,你想要字节。直接发送字节即可。如果您的协议是基于文本的,则可能需要使用bas64转换为字符串,然后使用诸如UTF8之类的编码转换为字节。这将适用于随机数据。如果没有base64,它将无法工作。 - usr
我想我的说法可能有点不清楚。这篇文章中的示例不是我正在使用的代码,我编写它是为了表明 Encoding.Unicode.GetBytes(Encoding.Unicode.GetString(randomBytes)) 有时会与 randomBytes 不同。我不想使用随机数据。我的输入是一个需要用 NetworkStream 发送的字符串。过程大致如下:input(string) => encryption => Send(NetworkStream) ,然后 Recieve(NetworkStream) => decryption => put string to use。byte[] 可以正常传递,但由于 Encoding 更改了它,解密无法正常工作。 - ido talker
为什么你不能完全使用字节进行操作?没有任何字符串。加密无论如何都不会对文本进行操作,而是对字节进行操作。@idotalker 我的观点并不取决于数据是否随机。我的观点是,如果你有任意字节,你不能使用编码将它们转换成文本。 - usr

1
任意字节数组并不一定编码成一个有效的Unicode字符串(详见https://en.wikipedia.org/wiki/UTF-16),例如:
  byte[] before = new byte[] { 0xA6, 0xDD };
  byte[] after = Encoding.Unicode.GetBytes(Encoding.Unicode.GetString(before));

  if (!before.SequenceEqual(after))
    Console.Write(string.Join(Environment.NewLine,
      $"before: {string.Join(" ", before.Select(b => b.ToString("x2")))}",
      $"after:  {string.Join(" ", after.Select(b => b.ToString("x2")))}"));

结果:

before: a6 dd
after:  fd ff

如果您想生成这些字符串,您可以修改您的代码为
while (true) {
  using (RandomNumberGenerator gen = new RNGCryptoServiceProvider()) {
    byte[] randomBytes = new byte[32];
    gen.GetBytes(randomBytes);

    byte[] after = Encoding.Unicode.GetBytes(Encoding.Unicode.GetString(randomBytes));

    if (!randomBytes.SequenceEqual(after)) {
      Console.Write(string.Join(" ", randomBytes) + 
                    Environment.NewLine + 
                    string.Join(" ", after));

      break;
    }
  }
}

可能的结果:
166 8 99 175 188 233 240 219 64 143 26 87 157 209 205 219 27 169 239 67 99 170 172 226 254 56 168 168 64 222 178 15
166 8 99 175 188 233 253 255 64 143 26 87 157 209 253 255 27 169 239 67 99 170 172 226 254 56 168 168 253 255 178 15
                     ^
                     Difference

请注意,我们应该使用SequenceEqual来比较数组。
如果您想编码一个数组,可以使用string.Join
byte[] array = ...

// Something like "166 8 99 175 188 233 240 219 ... 64 222 178 15"
string encoded = string.Join(" ", array);

byte[] back = encoded
  .Split(' ')
  .Select(item => byte.Parse(item))
  .ToArray();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接