使用ruby对大型csv文件进行流式处理和解压缩
我有一个问题,我需要下载,解压缩,然后逐行处理一个非常大的CSV文件。我认为让您了解文件有多大很有用:使用ruby对大型csv文件进行流式处理和解压缩,ruby,csv,io,net-http,rubyzip,Ruby,Csv,Io,Net Http,Rubyzip,我有一个问题,我需要下载,解压缩,然后逐行处理一个非常大的CSV文件。我认为让您了解文件有多大很有用: big_file.zip~700mb big_file.csv~23gb 以下是我希望发生的一些事情: 解压前不必下载整个文件 在解析csv行之前不必解压缩整个文件 在执行所有这些操作时,不要占用太多内存/磁盘 我不知道这是否可能。我是这么想的: require 'open-uri' require 'rubyzip' require 'csv' open('http://foo.b
- big_file.zip~700mb
- big_file.csv~23gb
- 解压前不必下载整个文件
- 在解析csv行之前不必解压缩整个文件
- 在执行所有这些操作时,不要占用太多内存/磁盘
require 'open-uri'
require 'rubyzip'
require 'csv'
open('http://foo.bar/big_file.zip') do |zipped|
Zip::InputStream.open(zipped) do |unzipped|
sleep 10 until entry = unzipped.get_next_entry && entry.name == 'big_file.csv'
CSV.foreach(unzipped) do |row|
# process the row, maybe write out to STDOUT or some file
end
end
end
以下是我所知道的问题:
读取整个响应并将其保存到一个openuri
中,对于这样大小的文件来说,这是不好的。我可能需要直接使用Tempfile
,但我不确定如何做到这一点,并且仍然会得到Net::HTTP
IO
- 我不知道下载速度有多快,也不知道
是否按照我展示的方式工作。当文件还没有全部存在时,它能解压部分文件吗Zip::InputStream
能否与rubyzip的CSV.foreach
一起工作?它的行为是否足够像InputStream
,能够解析出行?如果它想读取但缓冲区是空的,它会崩溃吗文件
我不知道这是否是正确的方法。也许一些EventMachine解决方案会更好(虽然我以前从未使用过EventMachine,但如果它能更好地用于类似的东西,我完全支持它)。我发布这个问题已经有一段时间了,如果其他人遇到它,我想我的发现可能值得分享
CSV
太慢了。我的csv文件非常简单,我不需要所有这些东西来处理带引号的字符串或类型强制。只需使用IO#gets
然后用逗号分隔行就容易多了Zip::Inputstream
。这是因为在文件的末尾有中央目录(EOCD)的结尾。这是提取文件所必需的,因此从http流式传输文件似乎不起作用unzip
包从zip文件流式传输未压缩的csv文件
require 'open3'
IO.popen('unzip -p /path/to/big_file.zip big_file.csv', 'rb') do |io|
line = io.gets
# do stuff to process the CSV line
end
unzip上的-p
开关将提取的文件发送到stdoutIO.popen
然后使用管道在ruby中使其成为IO
对象。很好用。如果您想要额外的处理,您也可以将它与CSV一起使用,它对我来说太慢了
require 'open3'
require 'csv'
IO.popen('unzip -p /path/to/big_file.zip big_file.csv', 'rb') do |io|
CSV.foreach(io) do |row|
# process the row
end
end
我认为,由于zip文件的结构,流式传输zip不会起作用。如果zip中只有一个文件(或者我想要的是第一个),它可能会执行类似于
funzip
的操作,但事实并非如此。