Linux 命令实战:探究不同文件格式的存储效率

237 阅读7分钟

因为最近实验室在承办一个会议,每个人都分配了一些活,我被分配到收集其中一个子活动的报名人员信息的任务,具体信息包括:姓名、机构、汇报标题、汇报摘要,既有中文也有英文

我需要将我收集到的信息发送到微信群里,因为正好电脑磁盘空间不够,正在清理磁盘,如果把这个信息新建一个 word 文档发送到群里,肯定会占用电脑存储,如果把一整段发到群里,又会给阅读前面的信息带来不便,我这时候想到 txt 格式比较省内存,但是省多少呢?我心中升起了这么一个疑问,正好看论文看得头疼,就开始研究了起来。

首先我创建了一个文件夹:DocStorageAnalysis,在里面创建了 txt、docx、md 格式的三个文件,并写入内容。

列出每个文件的大小:

  • 使用 stat 命令(status):

  • 使用 ls 命令(list):

  • 使用 du 命令(disk usage):

发现文件大小从小到大排序依次是 md, txt, docx,分别为:8705B,8706B,14882B。但是占用磁盘的大小与文件的小却不一样,分别为:12KB,12KB,16KB。为什么会这样呢?

文件的实际大小与其在磁盘上占用的空间之间的差异是由于文件系统如何分配磁盘空间造成的,文件的实际大小:这是文件内容的实际字节数,而文件系统将磁盘划分为一个个固定大小的块,通过块来分配磁盘空间。

使用 diskutil 工具来检查文件系统的信息,包括块大小:

这说明我电脑的文件系统使用 4096 字节(4KB)的块大小来分配磁盘空间。每个文件最少占用一个 4KB 的块,即使文件的实际大小小于 4KB。文件系统在分配磁盘空间时,按块(块大小)进行分配,这解释了为什么文件的实际大小和磁盘上占用的空间不一致。

回归主题,为什么使用三种格式存储相同的内容,文件的大小确不一样呢?具体差异体现在哪呢?

首先使用 word 工具对内容进行字符统计

微信使用 UTF-8 编码方式来处理文本内容,内容中包括中文字符、非中文字符(字母、数字)以及空格,在 UTF-8 编码中,中文字符占用 3B,非中文字符占用 1B(都是 ASCII 字符),空格也是 ASCII 字符,占用 1B。

经过计算,不考虑换行符的话,共占:1917 * 3 + (4433 - 1917) * 1 + (4825 - 4433) * 1 = 8659B

这样看来,使用 md 与 txt 格式存储,文件大小与纯文字编码大小的差距只有 46B 与 47B,为什么会有这个差距呢?

通过查阅相关资料,我将差别聚焦到了:换行符与文本元数据(md 格式还会有一些简单的标记符号来格式化文本,但是这次我在存储文本的时候没有对文本进行格式化,因此就不需要讨论此 md 标记符号带来的影响)。

因此我们需要查看文件具体内容是如何存储在文件系统中的,有哪些 Linux 命令可以实现此功能呢?

检索互联网之后发现有:cat命令、hexdump命令、xxd命令、od命令。

  • cat命令(Concatenate and Display Files):连接多个文件并打印到标准输出。macOS 中显示文件中的非打印字符、tab、换行符的命令是:cat -belnstuv information.docx,但是由于显示乱码,很不直观。
  • hexdump命令(Hexadecimal Dump):显示文件的十六进制编码,也不直观。
  • xxd命令(Hex Dump Utility):用于创建文件的十六进制表示(hex dump)并可以逆操作将十六进制表示转换回原始文件。它与 hexdump 类似,但功能更强大,特别是在进行反向转换时。
  • od命令(Octal Dump):输出文件的八进制、十六进制等格式编码的字节。

这里使用 od -c information.txt 指令来以字符形式显示文件内容。

左侧的是八进制偏移量,0000020就是 16B,0000040就是 32B,从右侧可以看到,一个汉字占用 3B,一个数字和换行符占用 1B。

然后使用 grep 命令(global search regular expression(RE) and print out the line)来搜索这段文本中的换行符 '\n'。(-o 的意思是:--only-matching,只输出文件中匹配到的部分。)

使用 wc 命令(word count)来统计匹配成功的字符数。(-l的意思是--lines,统计行数)

综上,也就是说 information.txt 文件中包括 47 个换行符。

同理可以看到,information.md 文件中包括 46 个换行符。

这也解释了为什么使用 md 与 txt 格式存储,文件大小与纯文字编码大小之间的差距为 46B 与 47B。

至于 docx 格式,它使用复杂的 XML 编码来存储内容和格式化信息,包含文档属性、修订历史、格式设置等元数据,以及丰富的格式化信息(例如字体、颜色、段落样式等),Word 文件实际上是一个 ZIP 压缩包,包含多个文件。

最后,回到最初的问题,怎样发到群里最节省存储空间呢?经过分析,发现是直接复制粘贴到输入框,但是这样会很挡住群消息。接下来最节省存储空间的是 txt 格式和 md格式(后来发现之所以 txt 格式比 md 格式多一个换行符,是因为在写入文件的时候不小心在 txt 格式中多换了一行,所以在不给 md 格式的文档加标记符号来定义格式的情况下,两者大小是一样的),两者占用存储空间一致,比纯文本编码只多了46B。而本次需要发送的信息不需要定义格式,因此选择以 txt 格式发送到微信群中是最好的选择。

附录:本文中涉及到的 Linux 命令:

  • stat 命令(status)
    用于显示文件或文件系统的详细状态信息,包括文件的大小、修改时间、权限等。
stat 文件名
  • ls 命令(list)
    用于列出目录的内容及其属性。
ls -l 文件名
  • du 命令(disk usage)
    用于显示文件或目录的磁盘使用情况。
du -h 文件名
  • diskutil 命令
    用于管理 macOS 系统的磁盘,检查文件系统的信息。
diskutil info /
  • cat 命令(Concatenate and Display Files)
    连接多个文件并打印到标准输出。macOS 中显示文件中的非打印字符、tab、换行符的命令是:
cat -belnstuv 文件名
  • hexdump 命令(Hexadecimal Dump)
    显示文件的十六进制编码。
hexdump -C 文件名
  • xxd 命令(Hex Dump Utility)
    用于创建文件的十六进制表示(hex dump)并可以逆操作将十六进制表示转换回原始文件。
xxd 文件名
  • od 命令(Octal Dump)
    输出文件的八进制、十六进制等格式编码的字节。
od -c 文件名
  • grep 命令(global search regular expression(RE) and print out the line)
    搜索文本中匹配的部分。
grep -o '\n' 文件名
  • wc 命令(word count)
    统计文件中的行数、字数和字符数。
wc -l 文件名