使用R获取文本文件中的行数

use*_*416 17 r file text-files

有没有办法在不导入文件的情况下获取文件中的行数?

到目前为止,这就是我正在做的事情

myfiles <- list.files(pattern="*.dat")
myfilesContent <- lapply(myfiles, read.delim, header=F, quote="\"")
for (i in 1:length(myfiles)){
  test[[i]] <- length(myfilesContent[[i]]$V1)
}
Run Code Online (Sandbox Code Playgroud)

但由于每个文件都很大,所以太耗费时间.

gag*_*ews 15

您可以在文件中计算换行符的数量(\n也适用\r\n于Windows).iff会给你一个正确的答案:

  1. 在最后一行末尾有一个换行符(BTW,read.csv如果不成立则发出警告)
  2. 该表在数据中不包含换行符(例如在引号内)

我只需要阅读部分文件即可.下面我设置chunk(tmp buf)大小为65536字节:

f <- file("filename.csv", open="rb")
nlines <- 0L
while (length(chunk <- readBin(f, "raw", 65536)) > 0) {
   nlines <- nlines + sum(chunk == as.raw(10L))
}
print(nlines)
close(f)
Run Code Online (Sandbox Code Playgroud)

关于ca.的基准 512 MB ASCII文本文件,12101000文本行,Linux:

  • readBin:大约 2.4秒

  • @ luis_js的wc解决方案:0.1秒.

  • read.delim:39.6秒.

  • 编辑:逐行读取文件readLines(f <- file("/tmp/test.txt", open="r"); nlines <- 0L; while (length(l <- readLines(f, 128)) > 0) nlines <- nlines + length(l); close(f)):32.0秒.

  • 这个给你.`wc`是三者中最快的,但并不是每个人都在Linux上. (3认同)

hrb*_*str 13

如果你:

  • 仍然希望避免一个system2("wc"…会导致的系统调用
  • 在BSD/Linux或OS X上(我没有在Windows上测试以下内容)
  • 不介意使用完整的文件名路径
  • 很舒服使用inline包裹

那么下面的内容应该尽可能快(它几乎wc是内联RC函数中的'行数'部分):

library(inline)

wc.code <- "
uintmax_t linect = 0; 
uintmax_t tlinect = 0;

int fd, len;
u_char *p;

struct statfs fsb;

static off_t buf_size = SMALL_BUF_SIZE;
static u_char small_buf[SMALL_BUF_SIZE];
static u_char *buf = small_buf;

PROTECT(f = AS_CHARACTER(f));

if ((fd = open(CHAR(STRING_ELT(f, 0)), O_RDONLY, 0)) >= 0) {

  if (fstatfs(fd, &fsb)) {
    fsb.f_iosize = SMALL_BUF_SIZE;
  }

  if (fsb.f_iosize != buf_size) {
    if (buf != small_buf) {
      free(buf);
    }
    if (fsb.f_iosize == SMALL_BUF_SIZE || !(buf = malloc(fsb.f_iosize))) {
      buf = small_buf;
      buf_size = SMALL_BUF_SIZE;
    } else {
      buf_size = fsb.f_iosize;
    }
  }

  while ((len = read(fd, buf, buf_size))) {

    if (len == -1) {
      (void)close(fd);
      break;
    }

    for (p = buf; len--; ++p)
      if (*p == '\\n')
        ++linect;
  }

  tlinect += linect;

  (void)close(fd);

}
SEXP result;
PROTECT(result = NEW_INTEGER(1));
INTEGER(result)[0] = tlinect;
UNPROTECT(2);
return(result);
";

setCMethod("wc",
           signature(f="character"), 
           wc.code,
           includes=c("#include <stdlib.h>", 
                      "#include <stdio.h>",
                      "#include <sys/param.h>",
                      "#include <sys/mount.h>",
                      "#include <sys/stat.h>",
                      "#include <ctype.h>",
                      "#include <err.h>",
                      "#include <errno.h>",
                      "#include <fcntl.h>",
                      "#include <locale.h>",
                      "#include <stdint.h>",
                      "#include <string.h>",
                      "#include <unistd.h>",
                      "#include <wchar.h>",
                      "#include <wctype.h>",
                      "#define SMALL_BUF_SIZE (1024 * 8)"),
           language="C",
           convention=".Call")

wc("FULLPATHTOFILE")
Run Code Online (Sandbox Code Playgroud)

它作为一个包更好,因为它实际上必须首次编译.但是,如果你确实需要"速度" ,它可以作为参考.对于189,955我躺在的行文件,我得到(来自一堆运行的平均值):

   user  system elapsed 
  0.007   0.003   0.010 
Run Code Online (Sandbox Code Playgroud)


Rui*_*das 12

这是使用CRAN封装的另一种方式fpeek,函数peek_count_lines。这个函数是用 C++ 编写的,速度相当快。

library(fpeek)
sapply(filenames, peek_count_lines)
Run Code Online (Sandbox Code Playgroud)


lui*_*_js 8

如果您使用的是Linux,这可能对您有用:

# total lines on a file through system call to wc, and filtering with awk
target_file   <- "your_file_name_here"
total_records <- as.integer(system2("wc",
                                    args = c("-l",
                                             target_file,
                                             " | awk '{print $1}'"),
                                    stdout = TRUE))
Run Code Online (Sandbox Code Playgroud)

在你的情况下:

#
lapply(myfiles, function(x){
                         as.integer(system2("wc",
                                            args = c("-l",
                                                     x,
                                                     " | awk '{print $1}'"),
                                            stdout = TRUE))
                      }
                  )
Run Code Online (Sandbox Code Playgroud)

  • 我不知道在 R 中还有其他方法可以做到这一点。系统调用会将控制权转移到系统,它会像系统使用 wc 和 awk 一样快。最后,R 非常适合快速原型设计和可视化数据。如果速度是一个问题,那么我会使用 C++,但这需要更多时间来编程 (2认同)

amb*_*odi 8

也许我缺少了一些东西,但是通常我会在ReadLines的顶部使用长度来完成它:

con <- file("some_file.format") 
length(readLines(con))
Run Code Online (Sandbox Code Playgroud)

至少在我遇到的许多情况下,这种方法已经奏效。我认为这有点快,它只会创建与文件的连接,而不会导入文件。

  • 它甚至可以写成一行:`length(readLines("some_file.format"))`。这也消除了再次关闭文件的必要性。但这里的问题是,这会将整个文件读取到内存中,这是询问者不想要的。 (3认同)

小智 5

我发现使用R.utils包的这种简单方法

library(R.utils)
sapply(myfiles,countLines)
Run Code Online (Sandbox Code Playgroud)

下面是它的工作原理