【问题标题】:Why reading a text file in lua returns only last chunk?为什么在 lua 中读取文本文件只返回最后一个块?
【发布时间】:2015-12-14 08:59:19
【问题描述】:

我正在尝试读取一个大文件并返回一个包含字数的表格。 我在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 对数据做了什么以及为什么这样做。有人能帮我弄清楚吗?

【问题讨论】:

    标签: lua


    【解决方案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 上读到的关于有效加载大文件的内容是正确的。但是该代码的编写假设您要加载一个块,然后处理该块,然后再加载另一个。

    你正在做的是逐块加载文件,然后将它们连接起来(好吧,你 没有实际上这样做,但这就是你想要的;)),然后处理整个文件。

    不是有效的。如果你想加载整个文件,然后在内存中处理整个文件,这就是read("*a") 的用途。

    【讨论】:

    • 我明白了,所以基本上我要做的就是if line then text = text .. data .. line .. '\n' end 才能使这个示例正常工作。我同意我最好使用read("*a"),只是想尝试一个例子。
    • 不,您应该与text 连接无论 line 是否为空。你的分配应该变成text = text .. data。是的,你应该只使用read("*a")
    • @minerals 如果你打算使用高效阅读方法那么你不应该使用*a 你不应该这样做 @987654335 @ 因为这与一口气读取整个文件几乎相同。只阅读整行的重点是,在处理之前不要将整个结果连接到最后,但你仍然会得到整个单词。效率的提升来自于从不将整个文件加载到内存中。
    【解决方案2】:

    您应该在 text = data 之后移动要在 while 循环内调用的字数统计代码。

    代码中的总体情况是文件以BUFSIZE 的块大小读取。然后应该处理该块,然后用下一个块替换该块。 因为你的所有工作都是在完成所有阅读之后完成的,所以你的字数统计功能只处理它读取的最后一个块,而不是所有块。

    【讨论】:

      猜你喜欢
      • 2010-10-04
      • 1970-01-01
      • 2023-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-07
      • 1970-01-01
      相关资源
      最近更新 更多