从sftp服务器以大块红宝石下载大型csv文件

时间:2018-07-06 04:59:27

标签: ruby csv sftp net-sftp

我要逐行下载和处理sftp服务器上的csv文件。 如果我正在使用下载!或sftp.file.open,它正在缓冲我要避免的整个数据。

这是我的源代码:

sftp = Net::SFTP.start(@sftp_details['server_ip'], @sftp_details['server_username'], :password => decoded_pswd)
  if sftp
    begin
      sftp.dir.foreach(@sftp_details['server_folder_path']) do |entry|
        print_memory_usage do
          print_time_spent do
            if entry.file? && entry.name.end_with?("csv")
              batch_size_cnt = 0
              sftp.file.open("#{@sftp_details['server_folder_path']}/#{entry.name}") do |file|
                header = file.gets
                header = header.force_encoding(header.encoding).encode('UTF-8', invalid: :replace, undef: :replace, replace: '')
                csv_data = ''
                while line = file.gets
                  batch_size_cnt += 1
                  csv_data.concat(line.force_encoding(line.encoding).encode('UTF-8', invalid: :replace, undef: :replace, replace: ''))
                  if batch_size_cnt == 1000 || file.eof?
                    CSV.parse(csv_data, {headers: header, write_headers: true}) do |row|
                      row.delete(nil) 
                      entities << row.to_hash       
                    end
                    csv_data, batch_size_cnt = '', 0
                    courses.delete_if(&:blank?)
                    # DO PROCESSING PART
                    entities = []
                  end
                end if header
              end
              sftp.rename("#{@sftp_details['server_folder_path']}/#{entry.name}", "#{@sftp_details['processed_file_path']}/#{entry.name}")
            end
          end
        end
end

有人可以帮忙吗?谢谢

1 个答案:

答案 0 :(得分:0)

您需要添加某种缓冲区才能读取大块,然后将它们全部写入。我认为拆分您的脚本解析和下载是明智的。当时只关注一件事:

您的原始行:

   ...
   sftp.file.open("#{@sftp_details['server_folder_path']}/#{entry.name}") do |file|
   ...

如果您检查download!中的source file(请不要忘记爆炸!),则可以使用'stringio'。您可以轻松调整的存根。通常,默认缓冲区为32kB就足够了。您可以根据需要进行更改(请参见示例)。

替换为(仅适用于单个文件):

StringIO的用法:

   ...
  io = StringIO.new
  sftp.download!("#{@sftp_details['server_folder_path']}/#{entry.name}", io.puts, :read_size => 16000))

或者您也可以下载文件

  ...
  file = File.open("/your_local_path/#{entry.name}",'wb')
  sftp.download!("#{@sftp_details['server_folder_path']}/#{entry.name}", file, :read_size => 16000)
  ....

在文档中,您可以使用选项:read_size

  

:read_size-一次从中读取的最大字节数   资源。增大此值可能会提高吞吐量。默认为   32,000字节。