5

我已经使用 gettextfile 方法从 ftp 服务器获取记录,并处理给定块中的每条记录,最终将其放在其他地方。

该文件是一个 CSV 文件,我需要使用 CSV 继续它以获取标题和数据,并在一些工作后将其放在数据库中。由于我有许多不同的文件,我需要一个通用的方法。我不想将所有记录加载到内存或磁盘上,因为文件可能非常大!所以流会很好

一个想法是为 CSV 提供一个 io 对象,但我不知道如何使用 Net::FTP 来做到这一点。

我已经看到“http://stackoverflow.com/questions/5223763/how-to-ftp-in-ruby-without-first-saving-the-text-file”,但它适用于 PUT。

有什么帮助吗?

4

3 回答 3

3

Justin 提到的技术创建了一个临时文件

你可以使用retrlines

   filedata = ''
   ftp.retrlines("RETR " + filename) do |block|
      filedata << block
   end

retrbinary代替:

   filedata = ''
   ftp.retrbinary("RETR " + filename, Net::FTP::DEFAULT_BLOCKSIZE) do |block|
      filedata << block
   end
于 2013-10-24T14:37:46.467 回答
1

我认为您是使用 gettextfile 解决问题的大部分方法。您可以将文件的一部分累积到一个Array.,然后在达到某个阈值时使用 CSV 处理它。这是一些未经测试的代码,一次处理十行:

current_line = 0
chunk = []

ftp.gettextfile('file.csv') do |line|
  chunk << line
  process_chunk!(chunk) if current_line % 10 == 0
  current_line += 1
end

process_chunk!(chunk) # Any remaining lines in final partial chunk

def process_chunk!(lines_in_chunk)
  # process partial chunk of lines as if it were the whole file
  lines_in_chunk = []
end

这对我来说似乎是更简单的解决方案之一,但您也可以在生产者-消费者模型中使用多个 unix 进程(写入和读取 STDOUT)或 Ruby 线程来解决问题。

于 2012-12-01T20:05:44.287 回答
0

我想出的解决方案是使用IO.pipe一个线程来迭代 FTP 文件中的文本行(其中一些可能是引号内的行片段)和putsIO 编写器的每一行。

在主线程中,我CSV基于 IO 读取器创建一个实例,并从中迭代解析的行。

require 'CSV'

def stream_ftp_csv_test(ftp, filename)
  read_io, write_io = IO.pipe

  fetcher = Thread.new do
    begin
      ftp.gettextfile filename do |line|
        write_io.puts line
      end
    ensure
      write_io.close
    end
  end

  csv = CSV.new(read_io, headers: :first_row)
  csv.each do |row|
    # Printing the row hashes here as an example.
    # You could yield each one to a given block
    # argument or whatever else makes sense.
    p row.to_h
  end

  fetcher.join
ensure
  read_io.close if read_io
end
于 2017-03-15T07:09:21.460 回答