我正在尝试读取一个大文件并返回一个包含字数的表。 我找到了一个在lua.org上有效读取大文件的例子,并提出了我的小脚本的最终版本。
function cnt_word(stream)
local BUFSIZE = 2^13 -- 8KB
local sin = io.input(stream) -- open input file
local wc = {}
local text = ""
while true do
local data, line = sin:read(BUFSIZE, '*l')
if not data then break end
if line then data = data .. line .. '\n' end
text = data
end
-- creating a table with word counts
for m in text:gmatch("%w+") do
if not wc[m] then wc[m] = 0 end
wc[m] = wc[m] + 1
end
return wc
end
input, word = arg[1], arg[2]
if not input then print("Error! Provide a valid filename") os.exit() end
if not word then print("Error! Provide a valid query term") os.exit() end
cnts = cnt_word(input)
cnt = cnts[word]
if not cnt then
print(string.format("'%s' not found in '%s'", word, input))
os.exit()
end
print(string.format("'%s' cnt: %s", word, cnt))
这个脚本的问题是它只返回文件的最后~70行,我无法弄清楚原因。行连接if line then data = data .. line .. '\n' end
执行〜3k次,这足以收集data
变量中的整个数据。然而,当我检查循环内data
的长度时,它不会增长但会在8k左右波动,而且当我检查text
的长度时,由于某种原因,它是〜3k。我不明白Lua对数据做了什么以及它为什么这样做。有人可以帮我搞清楚吗?
答案 0 :(得分:1)
考虑一下你的代码在做什么。
local data, line = sin:read(BUFSIZE, '*l')
您读取X字节数据,然后读取下一个结束行。
if not data then break end
如果没有读取数据,请返回。
if line then data = data .. line .. '\n' end
如果line
包含数据,则将其连接到总数中。
text = data
那么......你认为那是什么意思?我知道不做了什么。它不会连接数据块与已加载的数据。 已经替换该变量中的任何内容。
这意味着text
存储的最后一件事......是您加载的最后一个数据块。
关于效率的一句话。
您在Lua.org上阅读的关于有效加载大文件的内容是正确的。但是代码是假设你要加载一个块,然后进程那个块,然后加载另一个。
你正在做的是按块加载文件块,然后连接它们(好的,你不实际上正在那样做,但这就是你想要的;)),然后处理整个文件。
效率不高。如果你想加载整个文件,那么当它处于mempry时处理整个文件,这就是read("*a")
的用途。
答案 1 :(得分:0)
你应该在text = data
之后移动在while循环中调用单词计数的代码。
代码中总体上发生的是以BUFSIZE
的块大小读取文件。然后应该处理该块,然后用下一个块替换块。
因为所有的工作都是在完成所有读取后完成的,所以单词计数功能只处理它读取的最后一个块,而不是所有的块。