【问题标题】:Reading the last n lines from a huge text file从一个巨大的文本文件中读取最后 n 行
【发布时间】:2015-09-07 02:46:06
【问题描述】:

我尝试过类似的方法

file_in <- file("myfile.log","r")
x <- readLines(file_in, n=-100)

但我还在等……

任何帮助将不胜感激

【问题讨论】:

  • 可以想象你必须等待很长时间。负 n 值表示读取到文件末尾。如果该文件是 7.5 Gb,那么...

标签: windows r file-io


【解决方案1】:

我会使用scan,以防你知道日志有多少行:

scan("foo.txt",sep="\n",what="char(0)",skip=100)

如果你不知道你需要跳过多少,你别无选择,只能朝着其中一个方向前进

  • 读取所有内容并取最后 n 行(如果可行),
  • 使用scan("foo.txt",sep="\n",what=list(NULL)) 找出有多少条记录,或者
  • 使用某种算法遍历文件,每次只保留最后 n 行

最后一个选项可能如下所示:

ReadLastLines <- function(x,n,...){    
  con <- file(x)
  open(con)
  out <- scan(con,n,what="char(0)",sep="\n",quiet=TRUE,...)

  while(TRUE){
    tmp <- scan(con,1,what="char(0)",sep="\n",quiet=TRUE)
    if(length(tmp)==0) {close(con) ; break }
    out <- c(out[-1],tmp)
  }
  out
}

允许:

ReadLastLines("foo.txt",100)

ReadLastLines("foo.txt",100,skip=1e+7)

如果你知道你有超过 1000 万行。当您开始拥有非常大的日志时,这可以节省阅读时间。


编辑:事实上,考虑到文件的大小,我什至不会为此使用 R。在 Unix 上,您可以使用 tail 命令。在工具包中的某个地方也有一个 Windows 版本。不过我还没试过。

【讨论】:

  • 非常好的总结(+1)!我要补充一点,计算 R 之外的行(例如:Linux 中的wc)可能会更容易/更快。其他:我不明白while(1) {...} 的意思。这个循环会结束吗?
  • @daroczig :确实,它永远不会结束。丑陋的 hack,我知道,但如果我必须检查循环中间某处的条件,我会更频繁地使用它。事实上,对于这个问题,我会求助于 R 以外的其他工具,但这就是我在 R 中的做法。
  • @Joris Meys:感谢您的友好回答。现在我在你的循环中看到了break 部分,不知何故我忽略了它:) 抱歉打扰了。
  • 你知道tail的windows版本吗?
  • while(TRUE) 会更容易理解 - 不依赖于内部强制逻辑。
【解决方案2】:

您可以通过指定skip 参数来使用read.table 执行此操作。如果您的行不被解析为变量,请将分隔符指定为'\n',正如下面@Joris Meys 指出的那样,并设置as.is=TRUE 以获取字符向量而不是因子。

小例子(跳过前 2000 行):

df <- read.table('foo.txt', sep='\n', as.is=TRUE, skip=2000)

【讨论】:

  • 不错的 hack,但不要忘记使用 as.is=T。如果你设置 sep="\n" 就可以了,例如:read.table("foo.txt",sep="\n",as.is=T,skip=100)
  • 谢谢@Joris Meys,我已经根据您真正有用的评论更新了我的答案。
  • 如果我不知道要跳过多少行怎么办?该文件约为 7.5 GB。我错误地认为使用 -n, readlines 返回最后 n 行。它可以读取所有内容,这就是为什么花了这么长时间。
  • @gd047:我不会让 R 计算 7.5 Gb 文本文件的行数,我会为此使用快速的专用软件。我想计算 R 中的行会花费很多时间,但是使用例如Linux 中的wc 可以在几秒钟内解析文件。如果使用 Linux,您还可以从 R 调用 wc(请参阅:?system)。
  • @daroczig :为了它的价值,我会在 linux 中使用tail 命令:computerhope.com/unix/utail.htm
【解决方案3】:

您可以通过以下方法读取最后n行

第 1 步 - 根据需要打开文件 df &lt;- read.csv("hw1_data.csv")

第 2 步 - 现在使用 tail 函数从最后读取 n 行

tail(df, 2)

【讨论】:

    【解决方案4】:

    正如@JorisMeys 已经提到的,unix 命令tail 将是解决此问题的最简单方法。但是我想提出一个基于seekR 解决方案,从文件末尾开始读取文件:

    tailfile <- function(file, n) {
      bufferSize <- 1024L
      size <- file.info(file)$size
    
      if (size < bufferSize) {
        bufferSize <- size
      }
    
      pos <- size - bufferSize
      text <- character()
      k <- 0L
    
      f <- file(file, "rb")
      on.exit(close(f))
    
      while(TRUE) {
        seek(f, where=pos)
        chars <- readChar(f, nchars=bufferSize)
        k <- k + length(gregexpr(pattern="\\n", text=chars)[[1L]])
        text <- paste0(text, chars)
    
        if (k > n || pos == 0L) {
          break
        }
    
        pos <- max(pos-bufferSize, 0L)
      }
    
      tail(strsplit(text, "\\n")[[1L]], n)
    }
    
    tailfile(file, n=100)
    

    【讨论】:

      【解决方案5】:

      有些人已经说过了,但是如果你有一个很大的日志,最好只读入你需要的东西,而不是把它全部读入内存,然后对你需要的东西进行子集化。

      为此,我们使用 R 的 system() 来运行 Linux tail 命令。

      阅读日志的最后 10 行:

      system("tail path/to/my_file.log")
      

      阅读日志的最后两行:

      system("tail -n 2 path/to/my_file.log")
      

      读取日志的最后 2 行并将输出捕获到字符向量中:

      last_2_lines <- system("tail -n 2 path/to/my_file.log", intern = TRUE)
      

      【讨论】:

        【解决方案6】:

        查看最后几行:

        tail(file_in,100) 
        

        【讨论】:

          猜你喜欢
          • 2011-05-06
          • 2016-05-06
          • 2018-12-08
          • 2017-01-21
          • 2019-02-19
          • 1970-01-01
          • 2013-11-13
          相关资源
          最近更新 更多