10

我有这个代码:

Int32 i1 = 14000000;
byte[] b = BitConverter.GetBytes(i1);
string s = System.Text.Encoding.UTF8.GetString(b);
byte[] b2 = System.Text.Encoding.UTF8.GetBytes(s);
Int32 i2 = BitConverter.ToInt32(b2,0);;

i2 等于 -272777233。为什么不是输入值?(14000000) ?

编辑:我想要做的是将它附加到另一个字符串,然后我使用 WriteAllText 写入文件

4

5 回答 5

14

因为一个Encoding类不会只为任何事情工作。如果“字符”(在 UTF-8 的情况下可能是几个字节)在该特定字符集中(在您的情况下为 UTF-8)不是有效字符,它将使用替换字符

一个问号 (U+003F)

(来源:http: //msdn.microsoft.com/en-us/library/ms404377.aspx#FallbackStrategy

在某些情况下,它只是一个?,例如在 ASCII/CP437/ISO 8859-1 中,但您可以选择如何处理它。(见上面的链接)

例如,如果您尝试转换(byte)128为 ASCII:

string s = System.Text.Encoding.ASCII.GetString(new byte[] { 48, 128 }); // s = "0?"

然后将其转换回来:

byte[] b = System.Text.Encoding.ASCII.GetBytes(s); // b = new byte[] { 48, 63 }

不会得到原始的字节数组。

这可以作为参考:检查字符是否存在于编码中


我无法想象为什么需要将字节数组转换为字符串。这显然没有任何意义。假设您要写入流,您可以直接写入byte[]. yourIntegerVar.ToString()如果您需要在某些文本表示中使用它,那么将它转换为字符串并使用int.TryParse它来取回它是非常有意义的。


编辑:

可以将字节数组写入文件,但您不会将字节数组“连接”到字符串并使用惰性方法,因为它将处理编码转换,并且您可能最终会出现File.WriteAllText问号?你的文件。相反,打开一个FileStream并使用FileStream.Write直接写入字节数组。或者,您可以使用 aBinaryWriter直接写入二进制形式的整数(也可以是字符串),然后使用其对应项BinaryReader将其读回。

例子:

FileStream fs;

fs = File.OpenWrite(@"C:\blah.dat");
BinaryWriter bw = new BinaryWriter(fs, Encoding.UTF8);
bw.Write((int)12345678);
bw.Write("This is a string in UTF-8 :)"); // Note that the binaryWriter also prefix the string with its length...
bw.Close();

fs = File.OpenRead(@"C:\blah.dat");
BinaryReader br = new BinaryReader(fs, Encoding.UTF8);
int myInt = br.ReadInt32();
string blah = br.ReadString(); // ...so that it can read it back.
br.Close();

此示例代码将生成一个与以下 hexdump 匹配的文件:

00  4e 61 bc 00 1c 54 68 69 73 20 69 73 20 61 20 73  Na¼..This is a s  
10  74 72 69 6e 67 20 69 6e 20 55 54 46 2d 38 20 3a  tring in UTF-8 :  
20  29                                               )   

请注意,BinaryWriter.Write(string)还要在字符串前面加上它的长度,并且在回读时取决于它,因此不适合使用文本编辑器来编辑结果文件。(好吧,您正在以二进制形式写一个整数,所以我希望这是可以接受的?)

于 2013-01-05T02:49:23.187 回答
11

您不应该使用Encoding.GetString任意二进制数据转换为字符串。该方法仅适用于已使用特定编码编码为二进制数据的文本。

相反,您希望使用能够可逆地表示任意二进制数据的文本表示。两种最常见的方法是 base64 和 hex。Base64 是 .NET 中最简单的:

string base64 = Convert.ToBase64String(originalBytes);
...
byte[] recoveredBytes = Convert.FromBase64String(base64);

对此有几点注意事项:

  • 如果您想将此字符串用作 URL 参数,则应使用 web 安全版本的 base64;我不知道 .NET 中对此的直接支持,但您可能很容易找到解决方案
  • 只有当您确实需要字符串格式的数据时,您才应该这样做。如果您只是想将其写入文件或类似文件,最简单的方法是将其保存为二进制数据
  • Base64 不是很可读;如果您希望人类能够在不使用额外工具的情况下以文本形式读取数据,请使用十六进制。(关于将二进制数据转换为十六进制并返回的具体问题有很多。)
于 2018-03-05T08:35:16.720 回答
5

它不起作用,因为您正在向后使用编码。

编码用于将文本转换为字节,然后再次转换为文本。您不能将任意字节转换为文本。每个字符都有一个对应的字节模式,但每个字节模式都不会转换成一个字符。

如果您想要一种紧凑的方式将字节表示为文本,请使用 base-64 编码:

Int32 i1 = 14000000;
byte[] b = BitConverter.GetBytes(i1);
string s = Convert.ToBase64String(b);

byte[] b2 = Convert.FromBase64String(s);
Int32 i2 = BitConverter.ToInt32(b2, 0);
于 2013-01-05T03:10:46.140 回答
3

如果您的目标是将整数存储为字符串,然后返回整数,除非我遗漏了某些内容,否则以下内容还不够:

int32 i1 = 1400000;
string s = il.ToString();
Int32 i2 = Int32.Parse(s);
于 2013-01-05T02:52:55.540 回答
1

使长话短说:

您需要一种将每个字节值映射到唯一字符的编码,反之亦然。UTF8 字符的长度可以是 1 到 4 个字节,因此您不会存档该映射,您需要更基本的编码,例如 ASCII。不幸的是,原始的 ASCII 并没有这样做,它只是一个 7 位编码,只定义了低 128 个代码,上半部分(扩展代码)是特定于代码页的。要获得全范围的翻译,您只需要一个完整的 8 位编码,如代码页 437 或 850 或其他:

Int32 i1 = 14000000;
byte[] b = BitConverter.GetBytes(i1);
string s = System.Text.Encoding.GetEncoding(437).GetString(b);
byte[] b2 = System.Text.Encoding.GetEncoding(437).GetBytes(s);
Int32 i2 = BitConverter.ToInt32(b2,0);
于 2021-05-20T10:33:04.333 回答