【发布时间】:2016-06-20 12:50:12
【问题描述】:
我有一个包含 40,000 多行的大型数据文件。它是一个日志输入列表,看起来有点像这样:
D 20160602 14:15:43.559 F7982D62 Req Agr:131 Mra:0 Exp:0 Mxr:0 Mnr:0 Mxd:0 Mnd:0 Nro:0
D 20160602 14:15:43.559 F7982D62 Set Agr:130 Mra:0 Exp:0 Mxr:0 Mnr:0 Mxd:0 Mnd:0 Nro:0 I 20160602 14:15:43.559 F7982D62 GET 156.145.15.85:36773 xqixh8sl AES "/pcgc/public/Other/exome/fastq/PCGC0065109_HS_EX__1-04692__v3_FCAD2HMUACXX_L4_p1of1_P2.fastq.gz" ""
M 20160602 14:15:43.595 DOC1: F7982D62 Request for unencrypted meta data on encrypted transaction
M 20160602 14:15:48.353 DOC1: F7982D62 Transaction has been acknowledged at 722875647
F 20160602 14:15:48.398 F7982D62 GET 156.145.15.85:36773 xqixh8sl AES "/pcgc/public/Other/exome/fastq/PCGC0065109_HS_EX__1-04692__v3_FCAD2HMUACXX_L4_p1of1_P2.fastq.gz" "" 50725464 (4,32) "Remote Application: Session Aborted: Aborted by user interrupt"
M 20160602 14:15:48.780 DOC1: F7982D63 New download request D 20160602 14:15:48.780 F7982D63 META: 134 Path: /pcgc/public/CTD/exome/fastq/PCGC0033175_HS_EX__1-00304-01__v1_FCBC0RE4ACXX_L3_p32of96_P2.fastq.gz user: xqixh8sl pack: arg: feat: cE,s
既然它这么大,我不想把整个东西读入内存。我只需要以行标识符“F”开头并有 (0, 0) 错误的行,如下所示:
F 20160602 14:25:11.321 F7982D50 GET 156.145.15.85:37525 xqixh8sl AES "/pcgc/public/Other/exome/fastq/PCGC0077248_HS_EX__1-06808__v3_FCC49HJACXX_L7_p1of1_P1.fastq.gz" "" 3322771022 (0,0) "1499.61 seconds (17.7 megabits/sec)"
我可以忽略的所有其他内容。我的问题是:我想要一种方法来逐行读取此文件并评估它是否需要保留该行以供导入。目前,我正在使用for 循环遍历每一行并使用readLines() 函数。它看起来像这样:
library(stringr)
con <- file("dataSet.txt", open = "r")
Fdata <- data.frame
i <- 1
j <- 1
lineLength <- length(readLines(con))
for (i in 1:lineLength){
line <- readLines("dataSet.txt", 1)
if (str_sub(line, 1, 1) == 'F' && grepl("\\(0\\,0\\)", line)[i]){
print(line)
Fdata[j,] <- rbind(line)
i <- i + 1
j <- j + 1
}
i <- i + 1
}
print(Fdata)
它运行良好,但它给我的输出不是我想要的。它只是一遍又一遍地打印文件的第一行。
[1] "C 20160525 05:27:47.915 Rotated log file: /var/log/servedat-201605250527.log"
[1] "C 20160525 05:27:47.915 Rotated log file: /var/log/servedat-201605250527.log"
[1] "C 20160525 05:27:47.915 Rotated log file: /var/log/servedat-201605250527.log"
[1] "C 20160525 05:27:47.915 Rotated log file: /var/log/servedat-201605250527.log"
我怎样才能让它评估我是否需要这条线,以及如何正确存储它(作为向量、数据框、矩阵,这并不重要),以便我可以在外面打印它for循环?
更新
我已将代码更改为:
library(stringr)
con <- file("dataSet.txt", open = "r")
Fdata <- data.frame
i <- 1
j <- 1
lineLength <- length(readLines(con))
for (i in 1:lineLength){
line <- readLines(con, 1)
print(line)
if (str_sub(line, 1, 1) == 'F' && grepl("\\(0\\,0\\)", line)[i]){
print(line)
Fdata[j,] <- rbind(line)
i <- i + 1
j <- j + 1
}
i <- i + 1
}
print(Fdata)
但是,当我检查存储在行中的值时,它说它是空的。我不明白为什么它改变了。此外,它告诉我 if 语句没有正确的 TRUE/FALSE 条件,这也让我感到困惑,因为 grepl() 应该返回 TRUE/FALSE 值。
更新
我设法摆脱了错误,但是当我调用 Fdata 时仍然没有得到任何东西。我检查了我的变量,R 说那行是空的,它没有字符。我分配不正确吗?我希望 line 成为我在数据文件中解析并评估是否需要存储它的行。这是我更新的代码:
library(stringr)
con <- file("dataSet.txt", open = "r")
Fdata <- data.frame
i <- 1
j <- 1
lineLength <- length(readLines("dataSet.txt))
for (i in 1:lineLength){
line <- readLines(con, 1)
print(line)
if (str_sub(line, 1, 1) == 'F' && grepl("\\(0\\,0\\)", line)){
print(line)
Fdata[j,] <- rbind(line)
i <- i + 1
j <- j + 1
}
i <- i + 1
}
print(Fdata)
【问题讨论】:
-
您需要将文件连接传递到
readLines,而不是用字符串指定。将 for 循环中的第一行更改为line <- readLines(con, 1)应该可以解决这里的问题。 -
另外我认为你不需要转义逗号。使用
grepl("\\(0,0\\), line)。 -
您遇到的问题是
grepl("\\(0\\,0\\)", line)[i],其中i可能是一个很大的数字,而grepl 返回长度为1 的向量。删除[i]应该可以使其工作。 -
它消除了错误,但是当我调用 Fdata 时仍然没有打印任何内容。当我检查 line 变量时,R 一直说它是空的。我是不是分配错了?
-
您遇到的另一个问题是
lineLength <- length(readLines(con))。对于文件流,您只能读取一次,因为您在 for 循环之前已读取它,con指向文件末尾,因此您将在 for 循环中不再读取任何内容。而且你的程序两次读取文件,这似乎偏离了你构建整个想法的最初目的。请检查我在下面给出的答案。用你的文件名替换文件名。