如何将二进制文件读入数组

假设我有一个大小为90兆字节的文件。它没有加密,但是它是二进制的。

我想将这个文件存储到一个以字节值数组的形式来作为表格,这样我就可以按字节处理文件了。

我可以使用最多2 GB的内存,所以一些列出已处理的字节,尚未处理的字节以及处理过的字节的工具都是不错的。我并不在意处理的时间有多长。

我应该如何处理呢?

点赞
用户107090
用户107090

要将字符串s的内容分割成字节数组,请使用{s:byte(1,-1)}

2016-07-21 17:55:50
用户68204
用户68204

注意,由于Egor的评论,我已经扩展和重写了这个答案。

首先,您需要在二进制模式下打开文件。在Windows上,这个区别很重要,因为默认的文本模式会将行结束符从CR+LF变成C类型的换行符。您可以通过在io.open的模式参数中指定"rb"来实现此目的。

尽管您可以逐个字节地读取文件,但实际上您要以缓冲区的方式逐步处理文件。这些缓冲区可以相当大,但除非您知道自己仅处理小文件的一次性脚本,否则应避免使用file:read"*a"将整个文件读入缓冲区,因为这会造成非常大的文件会出现各种问题。

一旦您以二进制模式打开了文件,就可以使用buffer = file:read(n)读取其中一块,其中n是缓冲区中字节数的整数计数。使用一个中等大小的2的幂可能是最有效的。返回值要么为nil,要么是最多n字节的字符串。如果少于n字节,则这就是文件中的最后一个缓冲区。(然而,如果从套接字、管道或终端读取,读取少于n的字节可能只表明尚未到达数据,这取决于很多其他复杂因素,本句话中无法解释。)

buffer中的字符串可以以任何方式进行处理。只要#buffer不太大,则{buffer:byte(1,-1)}将为缓冲区中的每个字节返回一个整数字节值的数组。太大部分取决于Lua在构建时的配置方式,并且可能还取决于其他因素,例如可用内存。 #buffer > 1E6当然太大了。在下面的示例中,我使用buffer:byte(i)一次访问一个字节。这适用于任何大小的缓冲区,至少在i仍然是整数的情况下。

最后,别忘了关闭文件。

这是一个完整的轻度测试示例。它逐块读取文件,并累加所有字节的总大小和总和。然后打印大小、总和和平均字节值。

-- 将文件中的所有字节求和
local name = ...
assert(name, "Usage: "..arg[0].." filename")

file = assert(io.open(name, "rb"))
local sum, len = 0,0
repeat
    local buffer = file:read(1024)
    if buffer then
        len = len + #buffer
        for i = 1, #buffer do
            sum = sum + buffer:byte(i)
        end
    end
until not buffer
file:close()
print("长度:",len)
print("合计:",sum)
print("平均值:", sum / len)

在我使用此示例作为输入在Windows上运行Lua 5.1.4时,它报告如下:

长度: 402
合计: 30374
平均值: 75.557213930348
2016-07-21 21:26:15