当我将一个文本文件读入内存时,由于新的行,它会在末尾带有'\ n'文本。
["Hello\n", "my\n", "name\n", "is\n", "John\n"]
以下是我阅读文本文件的方式
array = File.readlines('text_file.txt')
我需要对这个文本数组进行大量的处理,所以我想知道在我第一次创建数组时是否应该删除“\ n”,或者当我使用regex对每个元素进行处理时,性能明智的。
我写了一些(不可否认的)测试代码来删除“\ n”
array = []
File.open('text_file.txt', "r").each_line do |line|
data = line.split(/\n/)
array << data
end
array.flatten!
如果我在第一次创建数组时删除“\ n”,有没有更好的方法呢?
如果我想将文件读入Set而不是(为了性能),是否有类似于readlines的方法呢?
答案 0 :(得分:4)
您需要运行基准测试,使用Ruby的内置Benchmark来确定您最快的选择。
然而,根据经验,我发现“啜饮”文件,即一次性读取,并不比使用IO.foreach
or File.foreach
的循环快。这是因为Ruby和底层操作系统会在读取时进行文件缓冲,从而允许循环从内存发生,而不是直接从磁盘发生。 foreach
不会为split
删除行终结符,因此如果您想改变行读取,则需要添加chomp
或chomp!
在:
File.foreach('/path/to/file') do |li|
puts li.chomp
end
或
File.foreach('/path/to/file') do |li|
li.chomp!
puts li
end
此外,啜食还存在不可扩展的问题;您最终可能会尝试读取比内存更大的文件,让您的机器瘫痪,而逐行阅读将永远不会这样做。
以下是一些表现数字:
#!/usr/bin/env ruby
require 'benchmark'
require 'fileutils'
FILENAME = 'test.txt'
LOOPS = 1
puts "Ruby Version: #{RUBY_VERSION}"
puts "Filesize being read: #{File.size(FILENAME)}"
puts "Lines in file: #{`wc -l #{FILENAME}`.split.first}"
Benchmark.bm(20) do |x|
x.report('read.split') { LOOPS.times { File.read(FILENAME).split("\n") }}
x.report('read.lines.chomp') { LOOPS.times { File.read(FILENAME).lines.map(&:chomp) }}
x.report('readlines.map.chomp1') { LOOPS.times { File.readlines(FILENAME).map(&:chomp) }}
x.report('readlines.map.chomp2') { LOOPS.times { File.readlines(FILENAME).map{ |s| s.chomp } }}
x.report('foreach.map.chomp1') { LOOPS.times { File.foreach(FILENAME).map(&:chomp) }}
x.report('foreach.map.chomp2') { LOOPS.times { File.foreach(FILENAME).map{ |s| s.chomp } }}
end
结果:
Ruby Version: 1.9.3
Filesize being read: 42026131
Lines in file: 465440
user system total real
read.split 0.150000 0.060000 0.210000 ( 0.213365)
read.lines.chomp 0.470000 0.070000 0.540000 ( 0.541266)
readlines.map.chomp1 0.450000 0.090000 0.540000 ( 0.535465)
readlines.map.chomp2 0.550000 0.060000 0.610000 ( 0.616674)
foreach.map.chomp1 0.580000 0.060000 0.640000 ( 0.641563)
foreach.map.chomp2 0.620000 0.050000 0.670000 ( 0.662912)
在今天的机器上,一个42MB的文件可以非常安全地读入RAM。我看到的文件比那些不适合我们某些生产主机内存的文件大得多。虽然foreach
较慢,但如果没有足够的内存,它也不会通过吸取所有内存来使机器瘫痪。
在Ruby 1.9.3上,使用map(&:chomp)
方法而不是旧形式的map { |s| s.chomp }
,速度要快得多。对于旧版本的Ruby来说,情况并非如此,因此需要注意。
另外,请注意,在我几年前的Mac Pro上,上述所有内容都在不到一秒的时间内处理了数据。总而言之,我要说担心加载速度是过早的优化,而真正的问题将是加载数据后所做的事情。
答案 1 :(得分:4)
我使用String#chomp:
lines = open('text_file.txt').lines.map(&:chomp)
答案 2 :(得分:0)
我希望在这些情况下使用strip over split,并且在第一次处理该行之后立即执行。在readline之后使用split是overkill imo。所以代码片段将是
array = []
File.open('text_file.txt', "r").each_line do |line|
array << data.strip
end
答案 3 :(得分:0)
如果您想摆脱结束换行符,可以String#chomp或String#rstrip。我首选的方法是chomp。
因此,您可以轻松地执行以下操作:
lines.map! { |line| line.chomp }
# or
lines.map! { |line| line.rstrip }
答案 4 :(得分:0)
mvelez@argo:~$ cat test.txt
Hello
my
name
is
John
一个班轮:
arr = File.open("test.txt",'r').read.split
在irb
irb(main):002:0> f = File.open("test.txt",'r')
=> #<File:test.txt>
irb(main):003:0> file_contents = f.read
=> "Hello\nmy\nname\nis\nJohn\n\n"
irb(main):004:0> file_contents.split
=> ["Hello", "my", "name", "is", "John"]