我认为您可以使用fread 的nrows 和skip 参数来自己做这件事。我没有适当损坏的 csv 来测试它,所以没有保证这会起作用,但可能类似于下面的东西。这基本上是一种尝试自动获取警告中标记的行号,并恢复读取该行之后所有行的csv。
基本上我一次读取 100,000 行数据,如果成功,我会将这些数据写入名为 data_chunks 的 list。如果它发出警告,我会拿起警告消息,使用一些正则表达式来确定行号是什么,然后阅读该行。然后我返回data.table 并写入data_chunks 列表。然后,我将rows_to_skip 值更新为data_chunks 中所有data.tables 中的行数,加上问题行数(我返回bad_row 布尔值以及data.table 以表明这一点,并且在每次迭代时将其添加到 bad_rows)。
它都在一个while循环中,所以会一直执行直到rows_to_skip的数量超过要读取的行数,在这种情况下,会抛出一个错误并且if语句会触发@987654337 @,然后退出循环。最后,使用rbindlist 将列表中的所有行绑定在一起。这感觉很 hacky,可能不是那么可靠,但为了将您的数据加载到 R 中,它至少可能是一个开始:
data_chunks <- list()
i <- 1
rows_to_skip <- 0
rows_to_read <- 100000
bad_rows <- 0
file_name <- "my.csv"
while (TRUE) {
out <- tryCatch(
list(
data = data.table::fread(file_name, nrows = rows_to_read, skip = rows_to_skip, header = FALSE),
bad_row = FALSE
),
error = function(e) {
e
},
warning = function(w) {
warn_msg <- conditionMessage(w)
warn_matches <- regexec("line (\\d+)", warn_msg)
rows_to_read <- as.numeric(regmatches(warn_msg, warn_matches)[[1]][2]) - 1
if (!is.na(rows_to_read)) {
list(
data = data.table::fread(file_name, nrows = rows_to_read, skip = rows_to_skip, header = FALSE),
bad_row = TRUE
)
} else {
NULL
}
})
if ("error" %in% class(out) || is.null(out)) {
break
} else {
data_chunks[[i]] <- out[["data"]]
}
bad_rows <- bad_rows + out[["bad_row"]]
rows_to_skip <- sum(sapply(data_chunks, nrow)) + bad_rows
i <- i + 1
}
mydata <- data.table::rbindlist(data_chunks, use.names = FALSE)