我正在尝试下载〜2GB的文件并将其写入本地文件,但是遇到了这个问题:
这是适用的代码:
File.open(local_file, "wb") do |tempfile|
puts "Downloading the backup..."
pbar = nil
open(backup_url,
:read_timeout => nil,
:content_length_proc => lambda do |content_length|
if content_length&.positive?
pbar = ProgressBar.create(:total => content_length)
end
end,
:progress_proc => ->(size) { pbar&.progress = size }) do |retrieved|
begin
tempfile.binmode
tempfile << retrieved.read
tempfile.close
rescue Exception => e
binding.pry
end
end
Run Code Online (Sandbox Code Playgroud)
导致问题的行在这里:
tempfile << retrieved.read
这会将整个内容读取到内存中,然后再将其写入tempfile. 如果内容很小,这没什么大不了的,但如果内容很大(多大取决于系统、配置、操作系统和可用资源),这可能会导致错误Errno::EINVAL,例如Invalid argument @ io_fread和Invalid argument @ io_write。
要解决此问题,请分块读取内容并将每个块写入tempfile. 像这样的东西:
tempfile.write( retrieved.read( 1024 ) ) until retrieved.eof?
Run Code Online (Sandbox Code Playgroud)
这将获取字节块1024并将每个块写入tempfile直到retrieved到达文件末尾(即.eof?)。
如果retrieved.read不带尺寸参数,您可能需要转换retrieved为 a StringIO,如下所示:
retrievedIO = StringIO.new( retrieved )
tempfile.write( retrievedIO.read( 1024 ) ) until retrievedIO.eof?
Run Code Online (Sandbox Code Playgroud)