Ruby ';无法分配内存';大数组错误

Ruby ';无法分配内存';大数组错误,ruby,arrays,memory-management,Ruby,Arrays,Memory Management,我正在尝试将一个大文本文件(大约200万行,260MB)导入数组,对数组进行编辑,然后将结果写入一个新的文本文件,方法是: file_data = File.readlines("massive_file.txt") file_data = file_data.map!(&:strip) file_data.each do |s| s.gsub!(/,.*\z/, "") end File.open("smaller_file.txt", 'w') do |f| f.wr

我正在尝试将一个大文本文件(大约200万行,260MB)导入数组,对数组进行编辑,然后将结果写入一个新的文本文件,方法是:

file_data = File.readlines("massive_file.txt")
file_data = file_data.map!(&:strip)
file_data.each do |s|
    s.gsub!(/,.*\z/, "")
end
File.open("smaller_file.txt", 'w') do |f|
    f.write(file_data.map(&:strip).uniq.join("\n"))
end

但是,我收到了错误
分配内存失败(NoMemoryError)
。如何分配更多内存来完成任务?或者,理想情况下,有没有另一种方法可以避免重新分配内存?

您可以尝试一次读写一行:

new_file = File.open('smaller_file.txt', 'w')
File.open('massive_file.txt', 'r') do |file|
  file.each_line do |line|
    new_file.puts line.strip.gsub(/,.*\z/, "")
  end
end
new_file.close

唯一挂起的是查找重复的行

您可以逐行读取文件:

require 'set'
require 'digest/md5'
file_data = File.new('massive_file.txt', 'r')
file_output = File.new('smaller_file.txt', 'w')
unique_lines_set = Set.new

while (line = file_data.gets)
    line.strip!
    line.gsub!(/,.*\z/, "")
    # Check if the line is unique
    line_hash = Digest::MD5.hexdigest(line)
    if not unique_lines_set.include? line_hash
      # It is unique so add its hash to the set
      unique_lines_set.add(line_hash)

      # Write the line in the output file
      file_output.puts(line)
    end
end

file_data.close
file_output.close
FILENAME="massive_file.txt"
MEGABYTE = 1024*1024

class File
  def each_chunk(chunk_size=MEGABYTE) # or n*MEGABYTE
    yield read(chunk_size) until eof?
  end
end

filedata = ""
open(FILENAME, "rb") do |f|
  f.each_chunk() {|chunk|
      chunk.gsub!(/,.*\z/, "")
      filedata += chunk
  }
end

或者,您可以分块读取文件,这比逐行读取文件要快:

require 'set'
require 'digest/md5'
file_data = File.new('massive_file.txt', 'r')
file_output = File.new('smaller_file.txt', 'w')
unique_lines_set = Set.new

while (line = file_data.gets)
    line.strip!
    line.gsub!(/,.*\z/, "")
    # Check if the line is unique
    line_hash = Digest::MD5.hexdigest(line)
    if not unique_lines_set.include? line_hash
      # It is unique so add its hash to the set
      unique_lines_set.add(line_hash)

      # Write the line in the output file
      file_output.puts(line)
    end
end

file_data.close
file_output.close
FILENAME="massive_file.txt"
MEGABYTE = 1024*1024

class File
  def each_chunk(chunk_size=MEGABYTE) # or n*MEGABYTE
    yield read(chunk_size) until eof?
  end
end

filedata = ""
open(FILENAME, "rb") do |f|
  f.each_chunk() {|chunk|
      chunk.gsub!(/,.*\z/, "")
      filedata += chunk
  }
end

ref:

如果我是你,我会把重点放在让它更加增量化上——没有必要一次性读取整个文件。正如@frederickheung建议的,你应该一次读取一行输入文件。您可以使用:
IO.foreach(“输入文件”)do | line |。。。结束
。转换块中的
,然后将其附加到输出文件中。您应该知道,您正在内存中制作数据的多个副本。在你的f行上写上“map”,“uniq”和“join”都将制作数据的完整副本,而“uniq”可能会将其删减。然而,当你乘以它时,260MB开始累积。在这里听取其他人的建议,简单地增量处理数据。根据您的需要,另一种方法可能是使用数据库。SQLite应该能够轻松地处理这么多的数据,而无需担心内存的使用。考虑到文件的大小,您应该将
唯一的\u行\u数组
设置为一个集合,而不是一个数组。还考虑为每行计算所设置的哈希代码的元素。注意,您需要初始化<代码>唯一行\u数组作为
唯一行\u字典
。是的,你做的一切都是对的。感谢您的提醒。更多潜在的改进:您可能不需要MD5哈希,
String#hash
就足够了。另外,你真的是指
而(line=file\u data)
?在我看来,您打算使用
while(line=file\u data.readline)
,但在到达文件末尾时会引发异常<代码>文件数据。每行do | line |可能是最好的。您还可以重写
line\u hash=Digest::MD5.hexdigest(line);如果不是唯一的_行_集。是否包括?行散列;唯一的\u行\u集。添加(行\u散列)仅为
如果唯一\u行\u集。添加?line.hash
最后,别忘了关闭
文件\u数据
文件\u输出
。如果我没有遗漏某些内容,您不会在输出文件的行之间插入
\n
,你可能想用
put
来代替
write
。我不太确定是否不需要md5——使用32位散列码,200万个值之间发生冲突的概率相当高(如果在64位平台上运行ruby,可能性更大)。遵循这种方法,删除重复行非常困难。