为什么open(“url”)有时会返回File有时候是StringIO?

时间:2014-08-15 05:20:50

标签: ruby file

我在S3上存储了两个CSV文件。当我open其中一个时,会返回File。当我open另一个时,会返回StringIO

fn1 #=> "http://SOMEWHERE.s3.amazonaws.com/setup_data/d1/file1.csv" 
open(fn1) #=> #<File:/var/folders/sm/k7kyd0ns4k9bhfy7yqpjl2mh0000gn/T/open-uri20140814-26070-11cyjn1> 

fn2 #=> "http://SOMEWHERE.s3.amazonaws.com/setup_data/d2/d3/file2.csv" 
open(fn2) #=> #<StringIO:0x007f9718670ff0> 

为什么呢?有没有办法用一致的数据类型打开它们?

我需要将相同的数据类型String传递给CSV.read(open(file_url)),如果有时它会获得File,有时会{{1} }}

它们是通过不同的ruby脚本创建的(它们包含非常不同的数据)。

在我的Mac上,它们似乎都是普通的文本CSV文件,它们通过AWS控制台上传,并具有相同的权限和相同的元数据(内容类型:application / octet-stream)。

2 个答案:

答案 0 :(得分:7)

这是设计的。如果对象的大小大于10240字节,则创建临时文件。来自source

StringMax = 10240
def <<(str)
  @io << str
  @size += str.length
  if StringIO === @io && StringMax < @size
    require 'tempfile'
    io = Tempfile.new('open-uri')
    io.binmode
    Meta.init io, @io if Meta === @io
    io << @io.string
    @io = io
  end
end

如果您需要StringIO个对象,可以使用fastercsv

答案 1 :(得分:1)

CSV::read期望文件路径作为其参数,而不是已打开的IO对象。然后它将打开文件并读取内容。您的代码适用于Tempfile案例,因为Ruby会在传递给to_path的任何内容后面调用File::open,并且File会响应此方法。会发生什么情况是CSV在同一文件上打开另一个 IO。

您可以创建一个新的CSV对象并在其上调用CSV::read(实例方法,而不是类方法),而不是使用readCSV:new正确处理IO对象:

CSV.new(open(file_url)).read