21.2.2 二进制文件

默认的简单模式总是以文本模式打开。在Unix中二进制文件和文本文件并没有区别,但是在如Windows这样的系统中,二进制文件必须以显式的标记来打开文件。控制这样的二进制文件,你必须将“b”标记添加在io.open函数的格式字符串参数中。在Lua中二进制文件的控制和文本类似。一个串可以包含任何字节值,库中几乎所有的函数都可以用来处理任意字节值。(你甚至可以对二进制的“串”进行模式比较,只要串中不存在0值。如果想要进行0值字节的匹配,你可以使用%z代替)这样使用*all模式就是读取整个文件的值,使用数字n就是读取n个字节的值。以下是一个将文本文件从DOS模式转换到Unix模式的简单程序。(这样转换过程就是将“回车换行字符”替换成“换行字符”。)因为是以二进制形式(原稿是Text Mode!!??)打开这些文件的,这里无法使用标准输入输入文件(stdin/stdout)。所以使用程序中提供的参数来得到输入、输出文件名。

local inp = assert(io.open(arg[1], "rb"))

local out = assert(io.open(arg[2], "wb"))

 

local data = inp:read("*all")

data = string.gsub(data, "\r\n", "\n")

out:write(data)

 

assert(out:close())

可以使用如下的命令行来调用该程序。

> lua prog.lua file.dos file.unix

第二个例子程序:打印在二进制文件中找到的所有特定字符串。该程序定义了一种最少拥有六个“有效字符”,以零字节值结尾的特定串。(本程序中“有效字符”定义为文本数字、标点符号和空格符,由变量validchars定义。)在程序中我们使用连接和string.rep函数创建validchars,以%z结尾来匹配串的零结尾。

local f = assert(io.open(arg[1], "rb"))

local data = f:read("*all")

local validchars = "[%w%p%s]"

local pattern = string.rep(validchars, 6) .. "+%z"

for w in string.gfind(data, pattern) do

    print(w)

end

最后一个例子:该程序对二进制文件进行一次值分析[6]Dump)。程序的第一个参数是输入文件名,输出为标准输出。其按照10字节为一段读取文件,将每一段各字节的十六进制表示显示出来。接着再以文本的形式写出该段,并将控制字符转换为点号。

local f = assert(io.open(arg[1], "rb"))

local block = 10

while true do

    local bytes = f:read(block)

    if not bytes then break end

    for b in string.gfind(bytes, ".") do

       io.write(string.format("%02X ", string.byte(b)))

    end

    io.write(string.rep("   ", block - string.len(bytes) + 1))

    io.write(string.gsub(bytes, "%c", "."), "\n")

end

如果以vip来命名该程序脚本文件。可以使用如下命令来执行该程序处理其自身:

prompt> lua vip vip

Unix系统中它将会会产生一个如下的输出样式:

6C 6F 63 61 6C 20 66 20 3D 20      local f =

61 73 73 65 72 74 28 69 6F 2E      assert(io.

6F 70 65 6E 28 61 72 67 5B 31      open(arg[1

5D 2C 20 22 72 62 22 29 29 0A      ], "rb")).

              ...

22 25 63 22 2C 20 22 2E 22 29      "%c", ".")

2C 20 22 5C 6E 22 29 0A 65 6E      , "\n").en

64 0A                              d.


相关链接:
lua程序设计目录 - 中国lua开发者 - lua论坛