我要逐行下载和处理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
有人可以帮忙吗?谢谢
答案 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字节。