如何同时逐行读取和写入文件?

时间:2019-02-21 02:33:03

标签: r connection readlines

我想从文件中删除以特定模式开头的所有行。我想用R做到这一点。优良作法是先读取整个文件,然后删除所有匹配的行,然后再写入整个文件,因为文件可能很大。因此,我想知道我是否可以同时对 same 文件进行读写连接(一直打开,一次打开一次?)。下面显示了该想法(但“挂起”并因此失败)。

## Create an example file
fnm <- "foo.txt" # file name
sink(fnm)
cat("Hello\n## ----\nworld\n")
sink()

## Read the file 'fnm' one line at a time and write it back to 'fnm'
## if it does *not* contain the pattern 'pat'
pat <- "## ----" # pattern
while(TRUE) {
    rcon <- file(fnm, "r") # read connection
    line <- readLines(rcon, n = 1) # read one line
    close(rcon)
    if(length(line) == 0) { # end of file
        break
    } else {
        if(!grepl(pat, line)) {
            wcon <- file(fnm, "w")
            writeLines(line, con = wcon)
            close(wcon)
        }
    }
}

注意:

1)如果有人写入新文件,请参见here。然后可以删除旧文件,然后将新文件重命名为旧文件,但这似乎不是很优雅:-)。

2)更新:以下MWE生成

Hello
world
-
world

请参阅:

## Create an example file
fnm <- "foo.txt" # file name
sink(fnm)
cat("Hello\n## ----\nworld\n")
sink()

## Read the file 'fnm' one line at a time and write it back to 'fnm'
## if it does *not* contain the pattern 'pat'
pat <- "## ----" # pattern
con <- file(fnm, "r+") # read and write connection
while(TRUE) {
    line <- readLines(con, n = 1L) # read one line
    if(length(line) == 0) break # end of file
    if(!grepl(pat, line))
        writeLines(line, con = con)
}
close(con)

2 个答案:

答案 0 :(得分:2)

我认为您只需要open = 'r+'。来自?file

  

模式

     

"r+""r+b"-打开以供读写。

我没有您的示例文件,因此,我将仅包含以下最小示例:

使用a-z在26行上获取文件,并用A-Z逐一替换:

tmp = tempfile()
writeLines(letters, tmp)
f = file(tmp, 'r+')
while (TRUE) {
  l = readLines(f, n = 1L)
  if (!length(l)) break
  writeLines(LETTERS[match(l, letters)], f)
}
close(f)

readLines(f)随后确认此方法有效。

答案 1 :(得分:2)

我知道您想使用R,但是以防万一您不知道,有一些非常简单的脚本工具可以胜任这种任务。例如gawk正是针对这种类型的操作而设计的,并且足够简单,即使没有任何先验知识,您也可以在几分钟内为此编写脚本。

这是在gawk(或awk,如果您在Unix上)中执行此操作的唯一方法:

gawk -i inplace '!/^pat/ {print}' foo.txt

当然,使用R在R内执行此操作很简单

system(paste0("gawk -i inplace '!/^", pat, "/ {print}' ", fnm))