如何在Ruby中处理大文件?

6

我是一个新手程序员,请多关照。我正在尝试从图书馆数据库.dat文件中提取IBSN号码。我已经编写了可行的代码,但它只搜索了大约180MB文件的一半。如何调整代码以搜索整个文件?或者如何编写一个程序来将dat文件分成易于管理的块?

编辑:以下是我的代码:

export = File.new("resultsfinal.txt","w+")

File.open("bibrec2.dat").each do |line|
  line.scan(/[a]{1}[1234567890xX]{10}\W/) do |x|
    export.puts x
  end
  line.scan(/[a]{1}[1234567890xX]{13}/) do |x|
    export.puts x
  end
end

@zed_0xff:Yoann Le Touche的方法没有将整个文件读入内存。 - Andrew Grimm
6个回答

4

你应该尝试捕获异常来检查问题是否真的在读取块上。

只是让你知道,我已经使用类似的语法编写了一个脚本,可以轻松搜索8GB大小的大文件而没有任何问题。

export = File.new("resultsfinal.txt","w+")

File.open("bibrec2.dat").each do |line|
  begin
    line.scan(/[a]{1}[1234567890xX]{10}\W/) do |x|
      export.puts x
    end
    line.scan(/[a]{1}[1234567890xX]{13}/) do |x|
      export.puts x
    end
  rescue
    puts "Problem while adding the result"
  end
end

3

主要的事情是清理和组合正则表达式以获得性能提升。此外,您应始终使用块语法来确保文件的fd被正确关闭。File#each不会将整个文件加载到内存中,它会一次读取一行:

File.open("resultsfinal.txt","w+") do |output|
    File.open("bibrec2.dat").each do |line|
        output.puts line.scan(/a[\dxX]{10}(?:[\dxX]{3}|\W)/)
    end
end

2
file = File.new("bibrec2.dat", "r")
while (line = file.gets)
  line.scan(/[a]{1}[1234567890xX]{10}\W/) do |x|
    export.puts x
  end
  line.scan(/[a]{1}[1234567890xX]{13}/) do |x|
    export.puts x
  end
end
file.close

1
关于性能问题,我没有看到文件大小有任何特别令人担忧的地方:180MB不应该造成任何问题。当您运行脚本时,内存使用情况会发生什么?
然而,我不确定您的正则表达式是否按照您的意愿工作。例如这个:
/[a]{1}[1234567890xX]{10}\W/

我认为这个意思是:

  • 匹配一个"a"。你真的想要匹配一个"a"吗?在这种情况下,只需要"a"就可以了,而不是"[a]{1}"。
  • 恰好10个数字或"x"或"X"
  • 一个单独的“非单词”字符,即不是a-z、A-Z、0-9或下划线

这里有几个示例ISBN匹配器herehere,尽管它们似乎更像我们在书的背面看到的格式,我猜测您的输入文件已经剥离了一些格式。


是的,原始数据文件已经重新格式化了ISBN,使它们呈现那种格式。我不知道为什么会这样做!只写“a”是个好主意,看起来简单多了。 - Nick

1
你可以考虑使用 File#truncateIO#seek 并采用二分查找算法。 #truncate 可能具有破坏性,因此您应该复制文件(我知道这很麻烦)。
middle = File.new("my_huge_file.dat").size / 2
tmpfile = File.new("my_huge_file.dat", "r+").truncate(middle)
# run search algoritm on 'tmpfile'
File.open("my_huge_file.dat") do |huge_file|
  huge_file.seek(middle + 1)
  # run search algorithm from here
end

这段代码高度未经测试,脆弱且不完整。但我希望它能为您提供一个构建平台。


如果你在一行的中间分割文件会怎样呢? ;) - fenec

-2
如果您在现代操作系统上进行编程,并且计算机具有足够的内存(例如512兆字节),那么Ruby应该没有问题将整个文件读入内存。
当您在典型的32位操作系统上达到约2 GB的工作集时,通常会出现问题。

我的电脑在Vista上使用4GB时有些不稳定,如果这有帮助的话。此外,它没有显示错误,只是显示了不完整的结果集。 - Nick
我相信他的意思是数据大小是4GB,而不是你的内存大小。32位操作系统无法处理超过大约3.5GB的RAM,因此你无论如何都没有4GB的可用工作RAM(除非你运行64位Vista)。如果你的数据集只有180MB,问题肯定在你的代码中。能否把脚本贴出来? - jkeys
没问题,我明天会发布它。非常感谢。 - Nick

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接