好的,让我们从您的代码的作用开始(请参阅我添加的 cmets):
// create a FileStream to data.txt (a file with a .txt extension - not necessarily a text file)
using (FileStream fs = File.Create("data.txt"))
// wrap the stream in the BinaryWriter class, which assists in writing binary files
using (BinaryWriter bw = new BinaryWriter(fs))
{
// create a 32-bit integer
int num = 2019;
// write a 32-bit integer as 4 bytes
bw.Write(num);
}
首先要注意的是,您不是在编写文本文件,而是在编写二进制文件。文件扩展名是一种约定,也许可以告诉我们应该在文件中找到什么,但它们不是福音真理。我可以复制Chrome.exe 并将其重命名为Chrome.txt,但这并不能使其成为文本文件。
我应该使用哪种编码方案才能在文本文件中看到 2019 年法案?
当我们谈论编码(例如 UTF-8)时,我们谈论的是文本编码 - 如何将文本转换为字节,但我们不处理代码中的文本,因此没有适用的文本用于查看二进制文件的编码格式。
BinaryWriter 相对于其他流适配器(例如 StreamWriter)的实际用途是什么?
它允许您从 .NET 中的值快速创建二进制格式。例如,您可以调用bw.Write(num);,而不必手动将int 值转换为4 个字节,同样您可以使用BinaryReader 和br.ReadInt32() 读取该数据。
你不能弄乱序列,如果你执行 ReadString(),你会得到一个有趣的字符。但是谁会“记住”或知道要阅读的序列?
当我们谈论“文件格式”时,我们通常指的是我们在读取文件时遵循的约定。我们可以启动应用程序、读取 ZIP 文件、收听 MP3 文件或查看位图的原因是因为我们使用的软件是为理解这些二进制格式而编写的。
如果我们以位图为例,描述文件格式的文档有很多。快速谷歌搜索显示this one、this one 和this one。您可以使用其中任何一个并创建一个程序来使用BinaryWriter 编写图像文件。
现在,如果您正在创建自己的格式,您可能会同时编写写入器和读取器,或者至少在编写读取器时查看写入器的代码(除非您有规范跟随,在这种情况下你可以使用它)。
但我不明白的是,我插入的int显示为一个有趣的字符,我插入的字符串实际上是可读的,那么为什么string是可读的而不是int?
当你调用Write(string) 时,你实际上是在写两件事:关于字符串长度的信息,然后是写字符串本身。为此,BinaryWriter 必须将字符串转换为字节,这在幕后为您完成。你可以阅读here和in the docs。
那么为什么你可以读取文件中的字符串呢?嗯,这是因为这里使用的文本编码与您可以用来编写文本文件的编码相同。您的文本编辑器将尽最大努力呈现整个文件的内容。如果您将任何类型的二进制文件(例如Chrome.exe)拖到文本编辑器中,您可以看到这一点。
那么您如何查看文件的内容?好吧,您可以使用hex editor。十六进制编辑器允许您查看和编辑二进制文件。十六进制编辑器通常会在一侧将您的文件显示为十六进制,而在另一侧尝试将其呈现为文本。
所以,想象一下你的代码是这样的:
using (FileStream fs = File.Create("data.txt"))
using (BinaryWriter bw = new BinaryWriter(fs))
{
int num = 2019;
bw.Write(num);
bw.Write("hello");
}
如果我们在十六进制编辑器中打开它,我们会看到以下内容。请注意,十六进制值之间的空格只是为了便于阅读,并不代表文件中的任何内容:
E3 07 00 00 05 68 65 6C 6C 6F
这里分为三个部分:
E3 07 00 00 - the hexadecimal expression of little endian 2019
05 - indicating that the string is 5 _bytes_ long
68 65 6C 6C 6F - the hexadecimal representations of each character of the string "hello"
您可以阅读有关字节顺序的信息here。可以把它想象成计算机是“从左到右”还是“从右到左”书写数字。
所以查看上面存储的 int 值,我们可以将其以 big-endian(右侧为 1)二进制形式编写为:
< 00 > < 00 > < 07 > < E3 >
0000 0000 0000 0000 0000 0111 1110 0011
然后我们可以将其计算回 2019 年,即您的原始值。
注意字符串长度信息可以多于一个 bye(按照this answer)。