6

只是为了分析我的 iis 日志(奖励:碰巧知道 iislog 是用 ASCII 编码的,errrr ..)

这是我的红宝石代码

1.readlines

Dir.glob("*.log").each do |filename|
  File.readlines(filename,:encoding => "ASCII").each do |line|
    #comment line
    if line[0] == '#'
      next
    else
      line_content = line.downcase
      #just care about first one
      matched_keyword = keywords.select { |e| line_content.include? e }[0]
      total_count += 1 if extensions.any? { |e| line_content.include? e }
      hit_count[matched_keyword] += 1 unless matched_keyword.nil?
    end
  end
end

2.打开

Dir.glob("*.log").each do |filename|
  File.open(filename,:encoding => "ASCII").each_line do |line|
    #comment line
    if line[0] == '#'
      next
    else
      line_content = line.downcase
      #just care about first one
      matched_keyword = keywords.select { |e| line_content.include? e }[0]
      total_count += 1 if extensions.any? { |e| line_content.include? e }
      hit_count[matched_keyword] += 1 unless matched_keyword.nil?
    end
  end
end

“readlines”读取 mem 中的整个文件,为什么“打开”总是更快一点?我在 Win7 Ruby1.9.3 上测试了几次

4

1 回答 1

22

两者readlines都只open.each_line读取一次文件。并且Ruby会对IO对象做缓冲,所以每次都会从磁盘读取一个块(例如64KB)的数据,以最小化磁盘读取的成本。磁盘读取步骤的耗时差异应该很小。

当您调用 时readlines,Ruby 会构造一个空数组[]并重复读取一行文件内容并将其推送到数组中。最后它将返回包含文件所有行的数组。

当您调用 时each_line,Ruby 会读取一行文件内容并将其交给您的逻辑。当您完成处理这一行时,ruby 会读取另一行。它重复读取行,直到文件中没有更多内容。

这两种方法的区别在于readlines必须将行附加到数组中。当文件很大时,Ruby 可能不得不复制底层数组(C 级别)以将其大小扩大一次或多次。

挖掘源代码,readlinesio_s_readlineswhich calls实现rb_io_readlinesrb_io_readlines调用rb_io_getline_1获取行rb_ary_push并将结果推送到返回数组中。

each_line是通过rb_io_each_line调用rb_io_getline_1fetch line 来实现的,就像readlines使用rb_yield.

因此,无需将行结果存储在不断增长的数组中each_line,也无需调整数组大小、复制问题。

于 2013-03-28T10:41:56.247 回答