繁体   English   中英

将 CSV 流从 Ruby 上传到 S3

[英]Upload CSV stream from Ruby to S3

我正在处理潜在的巨大 CSV 文件,我想从我的 Rails 应用程序中导出这些文件,并且由于它在 Heroku 上运行,我的想法是在生成这些 CSV 文件时将它们直接流式传输到 S3。

现在,我有一个问题,因为Aws::S3需要一个文件才能执行上传,而在我的 Rails 应用程序中,我想执行以下操作:

S3.bucket('my-bucket').object('my-csv') << %w(this is one line)

我怎样才能做到这一点?

您可以使用 s3 分段上传,通过将大对象拆分为多个块来允许上传。 https://docs.aws.amazon.com/AmazonS3/latest/dev/mpuoverview.html

分段上传需要更复杂的编码,但 aws-sdk-ruby V3 支持upload_stream方法,该方法似乎在内部执行分段上传,并且非常易于使用。 也许这个用例的确切解决方案。 https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Object.html#upload_stream-instance_method

client = Aws::S3::Client.new(
  region: 'ap-northeast-1',
  credentials: your_credential
)

obj = Aws::S3::Object.new('your-bucket-here', 'path-to-output', client: client)

require "csv"
obj.upload_stream do |write_stream|
  [
    %w(this is first line),
    %w(this is second line),
    %w(this is third line),
  ].each do |line|
    write_stream << line.to_csv
  end
end
this,is,first,line
this,is,second,line
this,is,third,line

upload_stream块的参数通常可以用作 IO 对象,它允许您像处理文件或其他 IO 对象一样链接和包装 CSV 生成:

obj.upload_stream do |write_stream|
  CSV(write_stream) do |csv|
    [
      %w(this is first line),
      %w(this is second line),
      %w(this is third line),
    ].each do |line|
      csv << line
    end
  end
end

或者,例如,您可以在生成和上传 CSV 时对其进行压缩,使用临时文件来减少内存占用:

obj.upload_stream(tempfile: true) do |write_stream|
  # When uploading compressed data, use binmode to avoid an encoding error.
  write_stream.binmode

  Zlib::GzipWriter.wrap(write_stream) do |gzw|
    CSV(gzw) do |csv|
      [
        %w(this is first line),
        %w(this is second line),
        %w(this is third line),
      ].each do |line|
        csv << line
      end
    end
  end
end

编辑:在压缩的示例代码中,您必须添加binmode以修复以下错误:

Aws::S3::MultipartUploadError: multipart upload failed: "\x8D" from ASCII-8BIT to UTF-8
s3 = Aws::S3::Resource.new(region:'us-west-2')
obj = s3.bucket.object("#{FOLDER_NAME}/#{file_name}.csv")
file_csv = CSV.generate do |csv|
    csv << ActionLog.column_names
    ActionLog.all.each do |action_log|
      csv << action_log.attributes.values
    end
  end
  obj.put body: file_csv

file_csv = CSV.generate是在 Ruby 中创建一串 CSV 数据。 创建这个CSV字符串后,我们使用bucket放入S3,路径为

#{FOLDER_NAME}/#{file_name}.csv

在我的代码中,我将所有数据导出到ActionLog模型。

我会看看http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/S3/S3Object.html#write-instance_method因为这可能是你正在寻找的。

编辑http://docs.aws.amazon.com/AmazonS3/latest/dev/UploadObjSingleOpRuby.html可能更相关,因为第一个链接指向 ruby​​ aws-sdk v1

require 'aws-sdk'

s3 = Aws::S3::Resource.new(region:'us-west-2')
obj = s3.bucket('bucket-name').object('key')

# string data
obj.put(body: 'Hello World!')

# IO object
File.open('source', 'rb') do |file|
  obj.put(body: file)
end

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM