首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从AWS S3下载文件时出现的文件编码问题

从AWS S3下载文件时出现的文件编码问题
EN

Stack Overflow用户
提问于 2018-08-08 21:38:30
回答 3查看 9.2K关注 0票数 5

我在AWS S3中有一个CSV文件,我试图在本地临时文件中打开该文件。这是代码:

代码语言:javascript
复制
s3 = Aws::S3::Resource.new
bucket = s3.bucket({bucket name})
obj = bucket.object({object key})
temp = Tempfile.new('temp.csv')
obj.get(response_target: temp)

它从AWS中提取文件,并将其加载到一个名为“tem.csv”的新的临时文件中。对于某些文件,obj.get(..)行引发以下错误:

代码语言:javascript
复制
WARN: Encoding::UndefinedConversionError: "\xEF" from ASCII-8BIT to UTF-8
WARN: /Users/.rbenv/versions/2.5.0/lib/ruby/2.5.0/delegate.rb:349:in `write'
/Users/.rbenv/versions/2.5.0/lib/ruby/2.5.0/delegate.rb:349:in `block in delegating_block'
/Users/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/aws-sdk-core-3.21.2/lib/seahorse/client/http/response.rb:62:in `signal_data'
/Users/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/aws-sdk-core-3.21.2/lib/seahorse/client/net_http/handler.rb:83:in `block (3 levels) in transmit'
...
/Users/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/aws-sdk-s3-1.13.0/lib/aws-sdk-s3/client.rb:2666:in `get_object'
/Users/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/aws-sdk-s3-1.13.0/lib/aws-sdk-s3/object.rb:657:in `get'

Stacktrace显示了最初由.get从AWS引发的错误。

我尝试过的事物:

当将文件(对象)上载到AWS S3时,可以指定content_encoding,因此我尝试将其设置为UTF-8:

代码语言:javascript
复制
obj.upload_file({file path}, content_encoding: 'utf-8')

另外,当您调用.get时,您可以设置response_content_encoding

代码语言:javascript
复制
obj.get(response_target: temp, response_content_encoding: 'utf-8')

这两项工作都不会导致上述相同的错误。我真希望这能起作用。在AWS S3仪表板中,我可以看到,通过代码确实正确地设置了内容编码,但这似乎没有什么区别。

在上面的第一个代码片段中,当我执行以下操作时,它确实可以工作:

代码语言:javascript
复制
temp = Tempfile.new('temp.csv', encoding: 'ascii-8bit')

但是我更喜欢用正确的编码从AWS S3上传和/或下载文件。有人能解释一下为什么在tempfile上指定编码有效吗?或者如何通过AWS S3上传/下载使其工作?

需要注意:错误消息中的问题字符似乎只是在我正在处理的这个自动生成文件的开头添加的随机符号。我并不担心正确地读取字符,它在解析文件时会被忽略。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-08-08 23:06:23

我没有完整的答案来回答你的所有问题,但我认为我有一个广义的解决方案,那就是总是将临时文件置于二进制模式。这样,AWS创业板将简单地将数据从桶中转储到文件中,而无需再进行任何重新/编码:

步骤1(将Tempfile放入绑定模式):

代码语言:javascript
复制
temp = Tempfile.new('temp.csv')
temp.binmode

但是,您将遇到一个问题,即您的UTF-8文件中现在有一个3字节的BOM头。

我不知道这个BOM是从哪里来的。上传文件的时候是在那里吗?如果是这样的话,在上传之前删除3字节的BOM可能是个好主意。

但是,如果您按照下面的方式设置系统,这并不重要,因为Ruby支持带BOM或不带BOM的UTF-8的透明读取,并且不管BOM头是否在文件中,都将正确返回字符串:

步骤2(使用bom\utf-8处理文件):

代码语言:javascript
复制
File.read(temp.path, encoding: "bom|utf-8")
# or...
CSV.read(temp.path,  encoding: "bom|utf-8")

我想这应该包括你所有的基地。无论您接收BOM + UTF-8或普通UTF-8编码的文件,您都将以这种方式正确地处理它们,不会在最终字符串中出现任何额外的标头字符,并且在用AWS保存它们时没有错误。

另一个选项(来自OP)

而是使用obj.get.body,这将绕过response_target和Tempfile的整个问题。

有用的参考资料:

Is there a way to remove the BOM from a UTF-8 encoded file?

How to avoid tripping over UTF-8 BOM when reading files

What's the difference between UTF-8 and UTF-8 without BOM?

How to write BOM marker to a file in Ruby

票数 7
EN

Stack Overflow用户

发布于 2019-09-12 09:29:58

另外,我通过使用File.open(tmp, 'wb')解决了这个编码问题。以下是它的样子:

代码语言:javascript
复制
s3_object = Aws::S3::Resource.new.bucket("bucket-name").object("resource-key")

Tempfile.new.tap do |file|
   s3_object.get(response_target: File.open(file, "wb"))
end
票数 1
EN

Stack Overflow用户

发布于 2018-08-13 17:53:19

Ruby文档中有一个将S3项下载到https://docs.aws.amazon.com/sdk-for-ruby/v3/developer-guide/s3-example-get-bucket-item.html文件系统的示例。我刚查过了,效果很好。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51756008

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档