使用ruby流式处理并解压缩大型csv文件

前端之家收集整理的这篇文章主要介绍了使用ruby流式处理并解压缩大型csv文件前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有问题需要下载,解压缩,然后逐行处理一个非常大的CSV文件.我认为让您了解文件的大小是有用的:

> 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

这是我所知道的问题:

> open-uri读取整个响应并将其保存到Tempfile中,这对于这个大小的文件来说是不合适的.我可能需要直接使用Net :: HTTP,但我不知道如何做到这一点仍然得到一个IO.
>我不知道下载的速度有多快,或者Zip :: InputStream是否按照我显示的方式工作.当它不是全部时,它可以解压缩一些文件吗?
> CSV.foreach可以使用rubyzip的InputStream吗?它是否足够像File一样可以解析行?如果它想要读取但缓冲区是空的,它会变得怪异吗?

我不知道这是否是正确的做法.也许一些EventMachine解决方案会更好(虽然我以前从未使用过EventMachine,但如果它对这样的东西更好用,我就是为了它).

解决方法

自从我发布这个问题已经有一段时间了,如果有人遇到它,我认为可能值得分享我发现的东西.

>对于我处理Ruby标准库CSV的行数太慢了.我的csv文件很简单,无论如何我都不需要处理引用的字符串或类型强制.只需使用IO#gets然后在逗号上拆分行就容易多了.
>我无法将整个事物从http流式传输到Zip :: Inputstream到包含csv数据的IO.这是因为zip file structure文件末尾有中央目录结束(EOCD).这是为了提取文件所需要的,因此从http流式传输它似乎不会起作用.

我最终使用的解决方案是将文件下载到磁盘,然后使用Ruby的open3库和Linux 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

解压缩时-p开关将提取文件发送到stdout. IO.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

猜你在找的Ruby相关文章