将CSV流从Ruby上传到S3

lin*_*ndy 10 ruby csv ruby-on-rails heroku amazon-s3

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

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

S3.bucket('my-bucket').object('my-csv') << %w(this is one line)
Run Code Online (Sandbox Code Playgroud)

我怎样才能做到这一点?

Mit*_*abe 11

您可以使用 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
Run Code Online (Sandbox Code Playgroud)
this,is,first,line
this,is,second,line
this,is,third,line
Run Code Online (Sandbox Code Playgroud)

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

this,is,first,line
this,is,second,line
this,is,third,line
Run Code Online (Sandbox Code Playgroud)

或者,例如,您可以在生成和上传 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
Run Code Online (Sandbox Code Playgroud)

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

Aws::S3::MultipartUploadError: multipart upload failed: "\x8D" from ASCII-8BIT to UTF-8
Run Code Online (Sandbox Code Playgroud)

  • @Kazuki你可以像这样传递参数。`s3obj.upload_stream(acl: 'private', content_type: 'text/csv; charset=UTF-8') do |stream| ...` s3obj 应该是这样的 `s3obj = Aws::S3::Object.new('your-bucket-name', path, client: client)` (2认同)

Duc*_*yen 5

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
Run Code Online (Sandbox Code Playgroud)

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

#{FOLDER_NAME}/#{file_name}.csv
Run Code Online (Sandbox Code Playgroud)

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

  • 这不能回答我的问题。我特别提到“流”。也请检查我对另一个答案的回复。 (7认同)

Nab*_*eel 2

我会看看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
Run Code Online (Sandbox Code Playgroud)

  • 那仍然是一个已经构建的文件。我想逐步上传文件的块。 (10认同)