究竟是什么决定了文件的类型

发布: (2025年12月13日 GMT+8 14:13)
4 min read
原文: Dev.to

Source: Dev.to

概览

每种文件格式都有一个规范——一种约定好的结构,定义了文件中字节的组织方式。就像我们有互联网协议的标准一样,也有文件类型的标准。当应用程序打开 PDF 或解析 PNG 时,它会按照该格式预先定义的规则读取字节。

我们通常通过文件扩展名(.zip.txt.jpg)来识别文件。扩展名仅仅是给人类和操作系统的提示;它们并不是唯一的真相。把 photo.jpg 重命名为 photo.png不会 将图像转换为 PNG 格式。

文件类型的真正判定是通过 魔数(magic numbers)完成的。

魔数

魔数是位于文件开头或特定偏移位置的一串字节,用作唯一签名来识别文件格式或类型。

每种文件格式都有约定好的魔数,应用程序在需要确定文件格式时会检查这些魔数,而不管文件的扩展名是什么。

  • PNG:89 50 4E 47
  • ZIP:50 4B 03 04
  • BMP:42 4D(ASCII 字符 “BM”)

下面是一个 Go 示例,读取一个 .bmp 扩展名的文件并验证其魔数,以确认它是否真的是位图图像:

package main

import (
    "bytes"
    "fmt"
    "io"
    "log"
    "os"
)

func main() {
    f, err := os.Open("sample.bmp")
    if err != nil {
        log.Fatal(err)
    }
    defer f.Close()

    // Read the first 2 bytes (the magic number)
    header := make([]byte, 2)
    if _, err := io.ReadFull(f, header); err != nil {
        log.Fatal(err)
    }

    // BMP signature is 0x42, 0x4D
    bmpSig := []byte{0x42, 0x4D}

    if bytes.Equal(header, bmpSig) {
        fmt.Println("Valid BMP detected")
    } else {
        fmt.Println("Invalid file format")
    }
}

Unix 的 file 命令正是利用这些签名来识别文件,而不考虑其扩展名。签名之后,大多数格式都会包含描述内容的元数据(图像的尺寸、音频的采样率、文档的作者信息等)。

文件结构的分类

文件格式大致可以分为以下几类结构:

  • 具有严格结构的二进制格式(PNG、JPEG、MP3):每个字节位置都有依据规范的特定含义。程序通过读取精确的偏移来解析这些文件。
  • 基于文本的结构化格式(JSON、XML、HTML、CSV):可读的文本,遵循语法规则。调试更方便,但文件体积相对较大。
  • 容器格式(ZIP、MP4、PDF):在单个文件内部充当文件系统,包含多个嵌入的文件或流。一个 MP4 可能包含独立的视频、音频和字幕轨道。DOCX 实际上是一个包含 XML 文件的 ZIP 包。

了解如何遍历字节并查阅规范,就能为许多文件类型编写自己的解析器。下一篇文章中,我将演示一个简单脚本,直接修改图像字节实现图像灰度化。

Back to Blog

相关文章

阅读更多 »