如何迭代文件?

时间:2013-12-08 20:45:25

标签: ruby file-io

我有一个看起来像这样的文件:

[noahc:~/projects/wordsquares] master(+87/-50)* ± cat wordlist/test_word_list.txt
card
apple
joe
bird
card
dart
area
rear
birdbird
after
boat
swim
north
abbe
byes
beep

如果我打开一个irb会话,我可以这样做:

2.0.0p247 :001 > file = File.open('./wordlist/test_word_list.txt', 'r')
 => #<File:./wordlist/test_word_list.txt>
2.0.0p247 :002 > file.readlines
 => ["card\n", "apple\n", "joe\n", "bird\n", "card\n", "dart\n", "area\n", "rear\n", "birdbird\n", "after\n", "boat\n", "swim\n", "north\n", "abbe\n", "byes\n", "beep \n", "\n"]

但是,现在我有一个名为WordSquareGenerator的类:

class WordSquareGenerator
  require 'pry'
  require 'pry-nav'
  require './lib/word_list_builder.rb'

  def initialize(n, file_location)
    @size_of_square = n
    @file = load_file(file_location)
    @word_stem_hash = WordListBuilder.new(n, @file).word_stem_hash
    @word_list = nil
  end

  def word_square_word_list
    binding.pry
    @file.each do |w|
      binding.pry
      @word_list ? break : solve_for_word_list([word])
    end
    binding.pry
  end

  def is_list_valid?(list)
    (0..@size_of_square - 1).each do |n|
      (0..@size_of_square - 2).each do |m|
        return false if list[n][m] != list [m][n]
      end
     end
    @generated_list = list unless @generated_list
  end

  def solve_for_word_list(word_array)
    if word_array.length == 4
      @word_list = word_array
    elsif @word_list
    else
      next_words = @word_stem_hash[word_array.map{|w| w[word_array.length]}.join]
      next_words.each do |word|
        solve_for_word_list(word_array + [word])
      end
    end
  end

private

  def load_file(file_location)
    File.open(file_location, 'r')
  end
end

当我运行word_square_word_list方法并点击第一个binding.pry时,我可以这样做:

2.0.0 (#<WordSquareGenerator:0x007ff3f91c16b0>):0 > @file.readlines
=> []

我为readlines得到一个空数组。怎么可能我得到两个不同的结果做同样的事情,除了一个在那个班级而另一个不在?

2 个答案:

答案 0 :(得分:1)

在阅读以下内容之前尝试运行:

@file.seek 0

您可能已经阅读了这些行,并且在再次阅读之前必须先找回文件的开头。

示例IRB会话:

irb(main):001:0> f = File.new 'test.txt' # already existing file
=> #<File:test.txt>
irb(main):002:0> f.readlines
=> ["this", "is", "a", "test"]
irb(main):003:0> f.readlines
=> []
irb(main):004:0> f.seek 0
=> 0
irb(main):005:0> f.readlines
=> ["this", "is", "a", "test"]

你甚至可以把它变成一种方法:

def readlines
  @file.seek 0
  @file.readlines
end

另外,请务必关闭文件(@file.close)!你应该只在尽可能短的时间内保持开放状态。你绝对不应该让它对整个程序开放。如果您不想担心这一点,只需将行存储在变量中,而不是保留文件:

@lines = File.open(file_location) {|f|
  f.readlines
}
# you could also use the shortcut form
# @lines = File.open(file_location, &:readlines)

答案 1 :(得分:1)

WordListBuilder,您可能已经在阅读该文件,当该操作返回WordSquareGenerator时,该文件已经到了结束,并且没有其他内容可供阅读。首先,不要做你现在正在做的事情,即打开文件,因为这会泄漏文件句柄(你没有在任何地方关闭它),而其他人读取句柄会导致你的代码失败。

以下是你如何做到的:

class WordSquareGenerator
  require 'pry'
  require 'pry-nav'
  require './lib/word_list_builder.rb'

  def initialize(n, file_location)
    @size_of_square = n
    @file_location = file_location
    @word_stem_hash = WordListBuilder.new(n, file_location).word_stem_hash
    @word_list = nil
  end

  def word_square_word_list
    binding.pry
    IO.foreach(@file_location) do |word|
      binding.pry
      @word_list ? break : solve_for_word_list([word])
    end
    binding.pry
  end

  def is_list_valid?(list)
    (0..@size_of_square - 1).each do |n|
      (0..@size_of_square - 2).each do |m|
        return false if list[n][m] != list [m][n]
      end
     end
    @generated_list = list unless @generated_list
  end

  def solve_for_word_list(word_array)
    if word_array.length == 4
      @word_list = word_array
    elsif @word_list
    else
      next_words = @word_stem_hash[word_array.map{|w| w[word_array.length]}.join]
      next_words.each do |word|
        solve_for_word_list(word_array + [word])
      end
    end
  end

end

您还需要更新WordListBuilder才能执行相同操作。这也有为您自动关闭文件句柄的优点,因此您不必自己关闭文件句柄。