我正在上传一个 CSV 文件,该文件在将行导入数据库时遇到问题:
Encoding::UndefinedConversionError ("\xCC" from ASCII-8BIT to UTF-8)
确保每列正确编码以放入数据库或忽略的最有效方法是什么?
最基本的方法是遍历每一行和每个字段并强制对字符串进行编码,但这似乎效率非常低。有什么更好的方法来处理这个问题?
目前它只是作为参数上传(
:csv_file
)。然后我按如下方式访问它:
CSV.parse(csv_file.download)
在模型内。
我假设在 activestorage 文件上调用 CSV.parse 时有一种方法可以强制编码,但不确定如何实现。有任何想法吗?
谢谢!
最新版本的 ActiveStorage (6.0.0.rc1) 添加了一个 API,能够将文件下载到临时文件,然后您可以从中读取。我假设 Ruby 将使用正确的编码从文件中读取。
https://edgeguides.rubyonrails.org/active_storage_overview.html#downloading-files
如果您不想升级到 Rails 6 的 RC(就像我一样),您可以使用此方法将字符串转换为 UTF-8,同时消除文件中可能存在的字节顺序标记:
wrongly_encoded_string = active_record_model.attachment.download
correctly_encoded_string = wrongly_encoded_string.bytes.pack("c*").force_encoding("UTF-8")
2023 年回来赞扬@eric-parshall 的回答。我的应用程序将完整的电子邮件正文(通常是原始 html)存储为 ActiveStorage 文件附件,并且在使用
.download
拉动这些正文以呈现它们时遇到了相当长的问题。 ruby 处理编码的方式始终意味着主体以 ASCII-8BIT
的编码进入,强制返回编码仍然会偶尔出现错误。
虽然 Eric 几年前在 Rails 6 上线之前就提到过这一点,但这个解决方案(以及不知何故的链接🤣)仍然非常有效。这是 Rails 7.1 文档的版本化链接,以防 Eric 的链接失效:
https://guides.rubyonrails.org/v7.1/active_storage_overview.html#downloading-files
埃里克提出的想法是完全正确的。如果您使用
.open
API 将附件保存到临时文件,然后使用 File.read
,您的编码问题可能会消失。看起来像这样:
eml = Email.last
eml.update!(
full_body: {
io: StringIO.new("This is a test!"),
filename: "full_body_test.html",
content_type: "text/plain"
}
)
# Before, using `#download`
content = eml.full_body.download
content.encoding #=> #<Encoding:ASCII-8BIT>
# After, using `#open`
content = nil
Email.last.full_body.open do |file|
content = File.read file
end
content.encoding #=> #<Encoding:UTF-8>
根据@JonSullivan的回答,我想添加以下内容来附加/上传文件,
file = params[:csv_import]
blob = ActiveStorage::Blob.create_and_upload!(
io: file,
filename: file.original_filename,
content_type: file.content_type
)
然后您可以使用 activestorage key 读取文件:
file_path = ActiveStorage::Blob.service.path_for(blob.key)
file = File.open(file_path, 'r')
CSV.foreach(file_path, headers: true, col_sep: ";") do |row|
puts row["fullname"]
puts row["id"]
end
ensure
file.close
end
问题就解决了,无需进行编码杂技。