CodeGym /课程 /C# SELF /文件格式:文本和二进制

文件格式:文本和二进制

C# SELF
第 35 级 , 课程 1
可用

1. 文本文件

想想看:电脑其实啥都存成1和0(或者说,不怕这个词的话——就是一串字节)。但如果你把同一个文件给两个程序用,它们可能反应完全不一样。比如一个程序能看到正常文本,另一个就只看到一堆“乱码字节”。这就是文件格式的问题——也就是这些字节到底怎么解释。格式描述了数据的内部结构、读取规则和编码方式。程序如果不知道格式,可能根本搞不懂文件里存的啥。

文本文件——就是那种数据直接用普通文本存的文件,用某种编码(最常见是UTF-8,或者硬核点用ASCII)。这种文件你用任何文本编辑器(比如Notepad或者VS Code)都能打开直接看——就是一行行字符,不是什么神秘的控制字节或者二进制结构。

常见例子

  • *.txt —— 普通文本文件,比如“to-do.txt”或者“best-books.txt”。
  • *.csv —— 数据用逗号或者分号分开的文件(很适合表格)。
  • *.json —— 用来交换结构化数据的文件(比如书单)。
  • *.xml,*.html —— 用来存和传结构化数据。

CSV文件例子


沙丘;弗兰克·赫伯特;1965
一九八四;乔治·奥威尔;1949
大师与玛格丽塔;米哈伊尔·布尔加科夫;1966
books.txt(CSV格式)内容示例

每一行就是一条记录(比如一本书)。行里的值用分号分开,这就是CSV(Comma-Separated Values)的例子。Comma本来是逗号,但这里用别的分隔符(;)。人能看到的字符,其实就是程序读到的字节,只要程序知道怎么解释文本格式和文件编码。

程序怎么操作文本文件

只要“按文本”打开文件,就能一行行读。例子(以后你会用到的):


// 从文件简单读取每一行(细节后面讲)
string[] lines = File.ReadAllLines("books.txt");
foreach (string line in lines)
{
    Console.WriteLine(line);
}

文本文件的优点

  • 人能直接看懂(human-readable)。
  • 手动编辑超方便(随便用Notepad都行)。
  • 调试和不同系统之间交换数据很爽。
  • 跨平台(Windows、Linux、Mac)搬来搬去没压力。

文本文件的缺点

  • 结构不严格(txt),格式错了很容易出bug。
  • 占空间大(比如数字12345 = 5字节,二进制只要4字节)。
  • 复杂数据(比如图片、音频)用文本传很麻烦甚至不行。
  • 性能:数据量大时慢。

有用小知识

  • 不同平台对“换行”理解不一样:Windows用\r\n,Unix用\n
  • 编码方式可能不同(UTF-8UTF-16ANSI等),所以一个系统写的文件在另一个系统可能全是“乱码”(其实就是字节解释错了)。

2. 二进制文件

二进制文件——文件里存的不是字符,而是任意字节。可以是数字、结构体、图片、音乐,甚至机器码。你试试用记事本打开.exe,全是看不懂的鬼画符!

常见例子

  • *.exe, *.dll —— 可执行文件和库。
  • *.jpg, *.png, *.gif—— 图片。
  • *.mp3, *.wav—— 音频文件。
  • *.dat —— 任意自定义数据文件。
  • 应用专用格式(*.docx*.xlsx等)——几乎都是二进制。

二进制文件是怎么存的?

程序一字节一字节地按自己需要的格式写和读数据。比如int类型的数字就是4字节(32位),字符串一般是长度+字符的字节(按某种编码)。

在文本文件里,数字12345就是字符'1'、'2'、'3'、'4'、'5'对应的字节:

字符 UTF-8编码
1 49
2 50
3 51
4 52
5 53

在二进制文件里,int 12345(小端序,little-endian)是这样:

位置 字节(hex)
0 0x39 57
1 0x30 48
2 0x00 0
3 0x00 0

(也就是说:12345 = 0x00003039。)

你可以试试把同一个数字用文本和二进制方式写到文件里——对比下文件大小。二进制会更小。

程序怎么操作二进制文件

要用专门的流(比如BinaryReaderBinaryWriter)。和文本文件不一样,必须完全知道结构,否则根本读不出来。


// 把数字写进二进制文件的例子
var writer = new BinaryWriter(File.Open("books.bin", FileMode.Create));

// 比如写字符串:先写字符数(int),再写字符的字节
string title = "沙丘";
writer.Write(title.Length); // 写长度(int)
writer.Write(title); // 写字符串(会用UTF-8)
writer.Write(1965); // 写年份(int)

writer.Close(); // 关闭流

这只是个例子。后面几节课我会详细讲二进制文件怎么搞。

二进制文件的优点

  • 更省空间:占用更小。
  • 读写速度快(尤其数据量大时)。
  • 能存复杂结构:数组、嵌套对象啥的都行。

二进制文件的缺点

  • 人看不懂(human-unreadable)。
  • 结构变了,老数据可能全废或者“炸了”。
  • 必须有详细的解析说明才能读。

3. 选哪种格式?

文本 vs 二进制文件

对比点 文本文件 二进制文件
人能看懂 不能
文件大小
通用性 高(随便编辑器) 只能用专门程序
速度
格式严格 不严格 必须严格
存结构 容易
数据损坏风险 低(能手动修) 高(出点错就全废)

怎么选

  • 想让数据人能看懂、方便改、方便调试?——用文本文件(比如.txt.csv.json)。
  • 数据复杂、对大小和速度有要求?——二进制格式。
  • 要跨平台交换数据?——文本更合适,但编码要用标准的(UTF-8)。
  • 程序要读写大量数据,而且格式很严格?——选二进制。

我们做的“书单”控制台小程序,一开始用文本格式(.csv.txt)就很合适。以后结构复杂了或者想加快加载速度,可以学二进制文件,或者用JSON/XML。

4. 有用的细节

生活中哪里会遇到文本和二进制文件?

文本文件:

  • 程序配置(经常是.ini.json)。
  • 脚本、日志、笔记。
  • 导入/导出文件(应用间数据交换)。

二进制文件:

  • 程序、游戏、库(一般人不会去看)。
  • 大型数据库和压缩包(比如.mdb.zip)。
  • 多媒体:音乐、照片、视频。

一次性读完整个文件(文本方式):


string allText = File.ReadAllText("books.txt");
// 现在allText就是整个文件内容的大字符串

按行读(适合列表):


string[] lines = File.ReadAllLines("books.txt");
foreach (string line in lines)
{
    // 可以把一行拆成几部分
    string[] parts = line.Split(';');
    // parts[0] —— 书名,parts[1] —— 作者,parts[2] —— 年份
}

二进制读取——必须按结构来


var reader = new BinaryReader(File.Open("books.bin", FileMode.Open));

int count = reader.ReadInt32(); // 书的数量
for (int i = 0; i < count; i++)
{
    string title = reader.ReadString();
    string author = reader.ReadString();
    int year = reader.ReadInt32();
    // 现在可以还原一条记录了!
}

reader.Close();

5. 实战例子:创建书单文件

把数据存到文本文件

我们每本书存成一行,格式是:
书名;作者;第一版年份


// 我们要保存的书单
var books = new List<(string Title, string Author, int Year)>
{
    ("沙丘", "弗兰克·赫伯特", 1965),
    ("一九八四", "乔治·奥威尔", 1949),
    ("大师与玛格丽塔", "米哈伊尔·布尔加科夫", 1966)
};

// 保存到文本文件
var writer = new StreamWriter("books.txt");
foreach (var book in books)
    writer.WriteLine($"{book.Title};{book.Author};{book.Year}");

writer.Close();

你可以用books.txt用记事本打开,直接看到所有数据。

把数据存到二进制文件

现在我们试试更紧凑的方式(虽然人看不懂):


var writer = new BinaryWriter(File.Open("books.bin", FileMode.Create));

writer.Write(books.Count); // 写书的数量
foreach (var book in books)
{
    writer.Write(book.Title); // 字符串:长度+字节
    writer.Write(book.Author); // 字符串
    writer.Write(book.Year); // 年份(int)
}

writer.Close();

你要是用文本编辑器打开books.bin,看到的就是一堆乱码。这很正常。二进制文件本来就不是给人看的——只有知道怎么写的程序才能正确处理。

6. 操作格式时常见的坑

你要是把二进制文件当文本读,看到的就是一锅粥或者直接报错。反过来,把文本文件当二进制读、还想有严格结构——也会出问题。

最常见的坑:数据结构和读写顺序不一致。比如先写了年份再写书名,结果读的时候顺序反了——拿到的就不是你想要的内容。一定要保证操作顺序一致!

很多程序员喜欢“偷看”文本文件,检查保存和加载逻辑——这也是文本格式新手阶段特别方便的原因。二进制更适合进阶用,或者你想让用户看不到存储细节。

2
任务
C# SELF, 第 35 级, 课程 1
已锁定
文本文件的写入与读取
文本文件的写入与读取
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION