Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用ruby对大型csv文件进行流式处理和解压缩_Ruby_Csv_Io_Net Http_Rubyzip - Fatal编程技术网

使用ruby对大型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

我有一个问题,我需要下载,解压缩,然后逐行处理一个非常大的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
以下是我所知道的问题:

  • openuri
    读取整个响应并将其保存到一个
    Tempfile
    中,对于这样大小的文件来说,这是不好的。我可能需要直接使用
    Net::HTTP
    ,但我不确定如何做到这一点,并且仍然会得到
    IO
  • 我不知道下载速度有多快,也不知道
    Zip::InputStream
    是否按照我展示的方式工作。当文件还没有全部存在时,它能解压部分文件吗
  • CSV.foreach
    能否与rubyzip的
    InputStream
    一起工作?它的行为是否足够像
    文件
    ,能够解析出行?如果它想读取但缓冲区是空的,它会崩溃吗

我不知道这是否是正确的方法。也许一些EventMachine解决方案会更好(虽然我以前从未使用过EventMachine,但如果它能更好地用于类似的东西,我完全支持它)。

我发布这个问题已经有一段时间了,如果其他人遇到它,我想我的发现可能值得分享

  • 对于我处理的行数,Ruby的标准库
    CSV
    太慢了。我的csv文件非常简单,我不需要所有这些东西来处理带引号的字符串或类型强制。只需使用
    IO#gets
    然后用逗号分隔行就容易多了
  • 我无法将整个内容从http流式传输到包含csv数据的
    Zip::Inputstream
    。这是因为在文件的末尾有中央目录(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
    
    unzip上的
    -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
    

    我认为,由于zip文件的结构,流式传输zip不会起作用。如果zip中只有一个文件(或者我想要的是第一个),它可能会执行类似于
    funzip
    的操作,但事实并非如此。