我试图以这种方式迭代文件的每一行:
@dump_users=File.open("#{@tmp_dir}path_to_file.txt","r")
puts "about to open file #{@dump_users.path} with size #{@dump_users.readlines.size}"
puts "calling gets: #{@dump_users.gets}"
while (user_line=@dump_users.gets) do
arr=user_line.split("t")
puts "About to add user: #{arr.inspect}"
query="INSERT INTO users VALUES (%s,"%s")" % [arr.at(0),arr.at(1).chop]
puts "Added users: #{arr.inspect}"
@db_3.execute(query)
end
第一行puts
打印正确的路径和文件的行数(362(,然后第二行"callinggets"不打印任何内容,并且实际上从未进入循环。
我做错什么了吗?
当您调用@dump_users.readlines
时,您正在将位置推进到文件的末尾。迭代前调用@dump_users.rewind
。
您所做的工作存在一些问题。我会像这样写未经测试的代码:
require 'sequel'
DB = Sequel.connect(@dsn)
path_to_file = File.join(@tmp_dir, "path_to_file.txt")
puts %Q[About to open "#{ path_to_file }"]
File.foreach(path_to_file) do |user_line|
arr = user_line.split("t")
puts "Adding user: #{arr.join(' ') }"
DB[:users].insert(fname: arr[0], lname: arr[1])
end
- 不要使用
open
,然后从不关闭文件,而是使用带有Ruby的IO或file类方法的块,在块退出时自动close
文件。这样可以保留系统资源 如果您需要知道有多少条目的话,可以逐行迭代文件,而不是将
open
与不可扩展的readlines
一起使用。foreach
的速度几乎(如果没有readlines
那么快的话(,并且如果您正在处理的文件大小为几百GB,则不会打开您的代码来消耗所有空间。例如,您可以使用对文件进行简单的飞行前检查,以查看需要读取的行数lines_in_file = 0 File.foreach('file_to_read') { lines_in_file += 1 } puts "There are #{ lines_in_file } lines."
如果您需要在插入前查看每一行,请使用比
inspect
更能控制的东西,例如一个简单的Stringformat
行:puts 'Adding user: %s %s' % [arr[0], arr[1]]
inspect
对调试很有用,但在生产代码中不有用,所以不要养成这种习惯。不要在数据库查询"插入"字符串中插入值。从不曾经如果该文件被泄露或来自未知/不安全的来源,则这是SQL注入攻击的直接途径。相反,至少应该使用占位符。但是,更好的方法是使用好的ORM,如Sequel,并让它处理生成与DBM接口所需的代码。它更容易,而且经过战斗考验。
@dump_users.readlines.size
将文件指针推进到文件的末尾。试着去掉那条线。
您需要删除对readlines
和gets
的调用。readlines
将推进文件指针以结束文件,然后gets
没有任何内容可读取并返回nil:
@dump_users=File.open("#{@tmp_dir}path_to_file.txt","r")
# puts "about to open file #{@dump_users.path} with size #{@dump_users.readlines.size}"
# puts "calling gets: #{@dump_users.gets}"
while (user_line=@dump_users.gets) do
arr=user_line.split("t")
puts "About to add user: #{arr.inspect}"
query="INSERT INTO users VALUES (%s,"%s")" % [arr.at(0),arr.at(1).chop]
puts "Added users: #{arr.inspect}"
@db_3.execute(query)
end