如何将二进制读取到数组中



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

我想把这个文件作为字节值的数组存储到一个表中,这样我就可以逐字节处理这个文件。

我最多可以腾出2 GB的内存,所以记下已经处理了哪些字节,哪些字节还没有处理,以及处理过的字节,这些都很好。我不太在乎处理可能需要多长时间。

我应该如何处理?

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

您首先需要以二进制模式打开文件。这一区别在Windows上很重要,默认文本模式将把换行符从CR+LF改为C换行。您可以通过为"rb"io.open指定模式参数来完成此操作。

尽管您可以一次读取一个字节的文件,但在实践中,您将希望在缓冲区中处理该文件。这些缓冲区可能相当大,但除非您知道在一次性脚本中只处理小文件,否则应避免使用file:read"*a"将整个文件读取到缓冲区中,因为这会导致非常大的文件出现各种问题。

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

buffer中的字符串可以通过多种方式进行处理。只要#buffer不太大,那么{buffer:byte(1,-1)}将为缓冲区中的每个字节返回一个整数字节值数组。太大在一定程度上取决于构建Lua副本时是如何配置的,也可能取决于其他因素,如可用内存。#buffer > 1E6当然太大了。在下面的示例中,我使用buffer:byte(i)一次访问一个字节。这适用于任何大小的缓冲区,至少只要i保持为整数。

最后,不要忘记关闭文件。

这里有一个完整的例子,经过了轻微的测试。它一次读取一个缓冲区中的文件,并累加总大小和所有字节的总和。然后打印大小、总和和平均字节值。

-- sum all bytes in a file
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("length:",len)
print("sum:",sum)
print("mean:", sum / len)

在我的Windows盒子上运行Lua 5.1.4,使用该示例作为输入,它报告:

长度:402总数:30374平均值:75.557213930348

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

相关内容

  • 没有找到相关文章

最新更新