从大文件中按行号读取行

27

我有一个包含1500万行的文件(无法放入内存)。我还有一个小向量,里面是我想要提取的行号。

如何一次性读取出这些行?

我希望有一个C语言函数能够在一次遍历中完成此操作。

5个回答

27

关键在于使用连接并在read.table之前打开它:

con<-file('filename')
open(con)

read.table(con,skip=5,nrow=1) #6-th line
read.table(con,skip=20,nrow=1) #27-th line
...
close(con)

您也可以尝试使用scan,它更快且提供更多的控制。


8
为了提高速度,建议使用scanreadLines函数。在R中,read.table函数会对数据类型、维度等进行大量检查。此外,最好不要将变量命名为c,因为它是R中最常用的函数之一(连接函数)。 - hatmatrix
这样只会从磁盘上读取文件一次吗?如果在skip=5之前调用了skip=20,read.table或scan会如何表现? - Aleksandr Levchuk
2
@Aleksandr 这很简单;首先,read.table将从连接中消耗skip+nrow行,下一个read.table将从此点开始。以此类推。 - mbq

5

如果它是二进制文件

关于此问题的讨论在这里:在 R 中仅读取 Stata .DTA 文件的一部分

如果它是 CSV 或其他文本文件

如果它们是连续的并且在文件顶部,只需使用 ,nrows 参数来调用 read.csv 或任何 read.table 家族中的函数。如果不是,您可以将 ,nrows,skip 参数组合起来,重复调用 read.csv(每次调用读入一行或一组连续的行),然后使用 rbind 将结果合并在一起。


能否一次通过完成这个任务? - Aleksandr Levchuk
@Aleksandr 绝对没错。但是 read.table 似乎并没有这样写。如果你查看 read.table 的源代码,会发现修改起来并不太难。也许其他人会有更好的答案,提供一个现成的函数来实现这个功能。 - Ari B. Friedman

4

如果您的文件具有固定的行长度,则可以使用“seek”跳转到任何字符位置。因此,只需为每个要读取的行跳转到N * line_length,并读取一行即可。

但是,根据R文档:

 Use of seek on Windows is discouraged.  We have found so many
 errors in the Windows implementation of file positioning that
 users are advised to use it only at their own risk, and asked not
 to waste the R developers' time with bug reports on Windows'
 deficiencies.

你也可以在C语言中使用标准C库中的'seek'函数,但我不知道上述警告是否适用!


哈哈,看到“不要在Windows缺陷上浪费R开发人员的时间”的提示,真是好笑。 - Nicholas Hamilton

3

在我得到R语言解决方案/答案之前,我已经用Ruby完成了它:

#!/usr/bin/env ruby

NUM_SEQS = 14024829

linenumbers = (1..10).collect{(rand * NUM_SEQS).to_i}

File.open("./data/uniprot_2011_02.tab") do |f|
  while line = f.gets
    print line if linenumbers.include? f.lineno 
  end
end

快速运行(尽可能快地读取文件)。


1
我不知道为什么这个被踩了。考虑到 Ruby 可以很容易地从 R 中调用,例如:http://www.r-bloggers.com/calling-ruby-perl-or-python-from-r/,同样地,从 Ruby 调用 R 也很容易,人们不应该回避使用最简单的解决方案。 - Carl Witthoft
当然,你可以使用 [http://beakernotebook.com] 并在 C++ 中进行。但是如果你能找到一个同样好的或者甚至慢10%的 R 本机解决方案,我会坚持使用它,除非你写了临时代码。否则阅读代码的人必须了解基本的 Ruby。否则,在不考虑兼容性的情况下,无法将代码移植到另一个系统中。可能会有安全问题等等。在不必要的情况下调用另一个进程通常不是一个好主意。我想说的是,最好只是在问题上添加注释(+链接)。 - Sergey Orshanskiy
如果你在一个语言中寻求解决方案,但提供的解决方案却是另一种语言,那么请考虑提供额外的代码来从一种语言调用另一种语言。 - JelenaČuklina

2

我根据这里的讨论 编译了一个解决方案

scan(filename,what=list(NULL),sep='\n',blank.lines.skip = F)

这只会显示行数,但不会读取任何内容。如果您真的想跳过空行,您可以将最后一个参数设置为TRUE。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接