0

我有一个创建 KML 文件的模型。我将该 KML 视为一个字符串,然后将其转发给 mailer,然后再将其发送:

def write_kml(coords3d, time)
  kml = String.new
    kml << header
    coords3d.each do |coords|
      coordinates = String.new
      coords.each do |coord|
        lat = coord[0].to_f
        lng = coord[1].to_f
        coordinates << "#{lng}" + "," "#{lat}" + ",0 "
        kml <<  polygon(coordinates)
      end
      end

    kml <<  footer
  kml

end

这在这里被使用:

  CsvMailer.kml_send(kml,time, mode, email).deliver

邮寄者:

  def kml_send(kml, time, mode, email)
    @time = (time / 60).to_i
    @mode = mode
    gen_time = Time.now
    file_name = gen_time.strftime('%Y-%m-%d %H:%M:%S') + " #{@mode.to_s}" + " #{@time.to_s}(mins)"
    attachments[file_name + '(KML).kml'] = { mime_type: 'text/kml', content: kml}
    mail to: email, subject: ' KML Filem'
  end

它占用了大量的内存。其中一些文件非常大(200MB),例如在 Heroku 上,它们占用了太多空间。

我有一些使用 S3 的想法,但我需要先创建这个文件,所以它仍然会使用内存。我可以不使用内存直接写入 S3 吗?

4

1 回答 1

1

您可以使用 s3 分段上传来执行此操作,因为它们不需要您预先知道文件大小。

部件的大小必须至少为 5MB,因此使用它的最简单方法是将数据写入内存缓冲区,并在每次超过 5MB 时将部件上传到 s3。上传的部分限制为 10000 个,因此如果您的文件大小将 > 50GB,那么您需要提前知道这一点,以便您可以使部分更大。

使用雾库,看起来有点像

def upload_chunk connection, upload_id, chunk, index
    md5 = Base64.encode64(Digest::MD5.digest(chunk)).strip
    connection.upload_part('bucket', 'a_key', upload_id, chunk_index, chunk, 'Content-MD5' => md5 )
end


connection = Fog::Storage::AWS.new(:aws_access_key_id => '...', :region => '...', :aws_secret_access_key => '...'
upload_id = connection.initiate_multipart_upload('bucket', 'a_key').body['UploadId']
chunk_index = 1

kml = String.new
kml << header
coords3d.each do |coords|
  #append to kml
  if kml.bytesize > 5 * 1024 * 1024
    upload_chunk connection, upload_id, kml, chunk_index
    chunk_index += 1
    kml = ''
  end
end
upload_chunk connection, upload_id, kml, chunk_index
#when you've uploaded all the chunks
connection.complete_multipart_upload('bucket', 'a_key', upload_id)

如果您创建了一个上传器类来包装缓冲区并将所有 s3 逻辑卡在其中,您可能会想出一些更简洁的东西。然后您的 kml 代码不必知道它是否具有实际字符串或定期刷新到 s3 的字符串

于 2013-07-01T12:49:50.507 回答