首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >BinaryWriter写有趣的人物

BinaryWriter写有趣的人物
EN

Stack Overflow用户
提问于 2019-07-10 06:56:46
回答 3查看 262关注 0票数 0

以下是代码:

代码语言:javascript
复制
using (FileStream fs = File.Create("data.txt"))
using (BinaryWriter bw = new BinaryWriter(fs))
{
   int num = 2019;
   bw.Write(num);
}

当我用编辑器打开data.txt时,我只看到一个有趣的角色。所以我的问题是:

Q1-这是因为我的编辑器的编码是UTF-8,与BinaryWriter格式不兼容吗?我应该使用哪种编码方案才能在文本文件中看到2019年法案?

Q2- BinaryWriter在其他流适配器(如StreamWriter )上的实际用途是什么?对于我来说,BinaryWriter做了一些奇怪的事情,例如,您首先使用BinaryWriter编写一个int,然后编写一个字符串……然后,当您通过BinaryReader读取文件时,您必须执行ReadInt32(),然后执行ReadString(),您不能搞乱序列,如果您执行ReadString(),就会得到一个有趣的字符。但是谁会“记住”或者知道要读的序列呢?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-07-10 11:44:27

好的,让我们从您的代码开始(请参阅我添加的注释):

代码语言:javascript
复制
// 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中的值快速创建二进制格式。例如,不必手动将int值转换为4个字节,您可以调用bw.Write(num);,同样,您也可以使用BinaryReaderbr.ReadInt32()读取数据。

你不能搞砸序列,如果你做ReadString(),你会得到一个有趣的角色。但是谁会“记住”或者知道要读的序列呢?

当我们谈论“文件格式”时,我们通常指的是我们在读取文件时遵循的约定。我们之所以可以启动应用程序、读取ZIP文件、侦听MP3文件或查看位图,是因为我们使用的软件是为了理解这些二进制格式而编写的。

如果我们以位图为例,有许多描述文件格式的文档。谷歌的快速搜索显示了这一个这一个这一个。您可以使用其中的任何一个,并创建一个程序,以编写一个图像文件使用BinaryWriter

现在,如果您正在创建自己的格式,您可能会同时编写作者和读者,或者至少在编写阅读器时向作者查看代码(除非您有一个规范,在这种情况下,您可以使用它)。

但我不明白的是,我插入的int是一个有趣的字符,我插入的字符串实际上是可读的,那么为什么字符串是可读的,而不是int呢?

当您调用Write(string)时,您实际上要编写两件事:关于字符串长度的信息,然后编写字符串本身。要做到这一点,BinaryWriter必须将字符串转换为字节,这是它在幕后为您所做的。你可以读到关于这里在医生里的文章。

那么,为什么可以读取文件中的字符串呢?这是因为这里使用的文本编码和写文本文件的编码是一样的。您的文本编辑器将尽最大努力呈现整个文件的内容。如果将任何类型的二进制文件(例如Chrome.exe)拖到文本编辑器中,则可以看到这一点。

那么,如何查看文件的内容呢?你可以用六角编辑器。十六进制编辑器允许您查看和编辑二进制文件。十六进制编辑器通常会将文件显示为十六进制,并试图将其呈现为另一侧的文本。

那么,假设您的代码是:

代码语言:javascript
复制
using (FileStream fs = File.Create("data.txt"))
using (BinaryWriter bw = new BinaryWriter(fs))
{
   int num = 2019;
   bw.Write(num);
   bw.Write("hello");
}

如果我们在一个十六进制编辑器中打开它,我们会看到以下内容。请注意,十六进制值之间的空格只是为了便于阅读,而不是文件中任何内容的表示:

代码语言:javascript
复制
E3 07 00 00 05 68 65 6C 6C 6F

这里有三个部分:

代码语言:javascript
复制
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"

你可以读到关于endianness 这里的文章。把它想象成一台计算机是写数字“左到右”还是“从右到左”。

因此,看看上面存储的int值,我们可以用大端(右侧的1)二进制写成如下:

代码语言:javascript
复制
<  00   >  <  00   >  <  07   >  <  E3   >
0000 0000  0000 0000  0000 0111  1110 0011

然后,我们可以将其计算回2019年,您的原始值。

注意,字符串长度信息可以是多个bye (按这个答案)。

票数 1
EN

Stack Overflow用户

发布于 2019-07-10 07:12:34

这都是文件格式的问题。

当您使用StreamWriter时,您的输出将是一个可读的文本,这意味着您可以看到编辑器中的内容。例如,当使用二进制写入器时,您可以编写bool "true""false",该值存储在其二进制表示中,对于布尔值是0或1。请注意,如果您愿意,可以在文本文件中为true编写"0"

当要记住内部的内容时,要么使用自描述的文件格式(例如带有头的csv ),要么使用标准格式(例如可以在网上找到描述的MP3 ),或者同时编写读取器和作者,以确保它们匹配(即使是文本格式)。

例如,通过查看"0,0",您无法判断它的两个布尔值是用逗号分隔,还是数字0以法语格式以一位精度分隔。

票数 1
EN

Stack Overflow用户

发布于 2019-07-10 12:15:49

文件是数字字符串--比如13,59,93。要理解文件的内容,您需要一种格式--本质上是对内容含义的说明。要查看文件的字节,可以使用十六进制编辑器(而不是文本编辑器)。

其中一种格式是文本文件。请注意,没有一种文本文件格式-正如您已经注意到的,您的文本编辑器允许您选择它在解释文本文件时将使用的编码。如果您选择了错误的编码,文本将是不同的(虽然您可能不会注意到大多数英文编码,因为许多字符在大多数现代编码中是相同的)。编码是将数字65 (实际上存储在文件中)转换为字符'A'的内容。除了编码之外,还有许多其他复杂的问题,我将稍后再讨论。

你在使用BinaryWriter。顾名思义,它的目的是编写二进制文件,而不是文本文件。如果要编写纯文本文件,请改用StreamWriter。二进制文件通常比文本文件更紧凑,可供特定应用程序使用,而不是由用户直接读取或修改。您仍然可以在二进制文件中写入文本--这正是bw.Write("Hello")所做的;由于它使用与文本编辑器相同的编码(默认情况下),所以在编辑器中实际上可以看到单词"Hello“。请注意,在"Hello“之前也有”有趣的字符“--但是对于这样短的字符串,它们是不可见的(有些可能显示为空格,另一些则显示为控制字符,如”行尾“或”制表符“;如果打印出文件,甚至可以写一个执行的beep )。这些表示以下字符串的长度,它允许您快速读取字符串,并且只读取字符串(或者在读取文件时跳过字符串)。

现在,读写文件需要一定的对称性。正如您注意到的,如果您将文件写为“数字优先,然后是字符串”,则还需要将其读取为“数字优先,然后是字符串”。不管该文件是文本文件还是二进制文件--例如,假设您想将GPS写到文件中。如果您先编写延迟,然后编写经度,另一个程序(或用户)首先将文件读取为经度,则会得到错误的结果。这种简单的文件格式依赖于顺序,完全不能容忍任何错误--在读或写时跳过一行,整个文件就变得完全不可读了。

但是,当然,这并不是设计文件格式的唯一方法(尽管它非常常见)。有些格式显式地设计为不那么严格。例如,可以将数据保存在JSON文件中,而不是一组行或逗号分隔的值:

代码语言:javascript
复制
{
  "longitude": 12.365,
  "lattitude": 32.131
}

主要的好处是这种格式更具有自描述性和可读性(和可写性);您一眼就可以看到延迟是32.131。应用程序仍然需要理解什么是“延迟”,但您可以看到这里肯定有进展。对于某些类型的更改,它也更宽容--例如,读者应用程序不必关心某些字段是否丢失(并显示信息不完整,而不是完全混乱),或者是否添加了新字段。它不关心田地的顺序。

这是有代价的。该文件要大得多(一个简单的二进制文件可以是8字节或更少,与示例JSON的~40字节相比,这一点更加明显,如果涉及数组等)。对于一个程序来说,解析要困难得多,这可能会使加载文件的速度变慢。不严格的格式也有它的好处和诅咒-它可能很难确保程序正确处理所有潜在的输入,特别是如果有多个不同的读者和作者。

二进制文件格式也是相当的,目前最流行的是Protobuf。它不完全是自我描述的,不容易被人类阅读,但它也更严格,更有效的空间和更快的读写速度。

最后,你需要选择你想要用来保存东西的格式。每一个国家都有自己的优点和缺点。有些非常简单,比如仅仅使用BinaryWriter编写一个著名的序列.有些支持版本兼容性,因此较新的应用程序可以读取或写入旧应用程序的文件,反之亦然。有些是专门针对某些用途进行优化的,比如在文件的内容中启用快速搜索,或者高效地存储图像。有些主要是为了易于使用而设计的(如JSON和Protobuf,或.NET的BinarySerializer)。

但最终,文件只是一串数字。你需要规则来解释这些数字是有用的。选择适合你需要的规则。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56964971

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档