我必须处理的数据包含带有一些额外\ r字符的非加引号文本。文件很大(500MB),大量(> 600),并且不能更改导出。数据可能看起来像
A,B,C
嗒嗒,A,1
布卢,一个\ R,B
blee,C,d
fread
来处理这个问题? library(data.table)
csv<-"A,B,C\r\n
blah,a,1\r\n
bloo,a\r,b\r\n
blee,c,d\r\n"
fread(csv)
fread(csv)出错: 当检测到来自0点的类型时,预期的sep(',')但新行,EOF(或其他非打印字符)结束字段1: 布卢,一
简单的复制可能太微不足道了,无法给出规模感......
samplerecs<-c("blah,a,1","bloo,a\r,b","blee,c,d")
randomcsv<-paste0(c("A,B,C",rep(samplerecs,2000000)))
write(randomcsv,file = "sample.csv")
# Naive approach
fread("sample.csv")
# Akrun's approach with needing text read first
fread(gsub("\r\n|\r", "", paste0(randomcsv,collapse="\r\n")))
#>Error in file.info(input) : file name conversion problem -- name too long?
# Julia's approach with needing text read first
readr::read_csv(gsub("\r\n|\r", "", paste0(randomcsv,collapse="\r\n")))
#> Error: C stack usage 48029706 is too close to the limit
答案 0 :(得分:4)
继续@ dirk-eddelbuettel&amp; @nrussell的建议,解决这个问题的方法是预处理文件。处理器也可以在fread()中调用,但在这里它是以单独的步骤执行的:
samplerecs<-c("blah,a,1","bloo,a\r,b","blee,c,d")
randomcsv<-paste0(c("A,B,C",rep(samplerecs,2000000)))
write(randomcsv,file = "sample.csv")
# Remove errant `\r`'s with tr - shown here is the Windows R solution
shell("C:/Rtools/bin/tr.exe -d '\\r' < sample.csv > sampleNEW.csv")
fread("sampleNEW.csv")
答案 1 :(得分:2)
我们可以尝试gsub
fread(gsub("\r\n|\r", "", csv))
# A B C
#1: blah a 1
#2: bloo a b
#3: blee c d
答案 2 :(得分:1)
如果您愿意,也可以使用tidyverse软件包执行此操作。
> library(readr)
> library(stringr)
> read_csv(str_replace_all(csv, "\r", ""))
# A tibble: 3 × 3
A B C
<chr> <chr> <chr>
1 blah a 1
2 bloo a b
3 blee c d
答案 3 :(得分:1)
如果你确实想在R中完成它,你可以尝试使用连接。只要连接保持打开,它就会从其先前的位置开始读/写。当然,这意味着打开和关闭连接的负担落在你身上。
在以下代码中,文件由块处理:
library(data.table)
input_csv <- "sample.csv"
in_conn <- file(input_csv)
output_csv <- "out.csv"
out_conn <- file(output_csv, "w+")
open(in_conn)
chunk_size <- 1E6
return_pattern <- "(?<=^|,|\n)([^,]*(?<!\n)\r(?!\n)[^,]*)(?=,|\n|$)"
buffer <- ""
repeat {
new_chars <- readChar(in_conn, chunk_size)
buffer <- paste0(buffer, new_chars)
while (grepl("[\r\n]$", buffer, perl = TRUE)) {
next_char <- readChar(in_conn, 1)
buffer <- paste0(buffer, next_char)
if (!length(next_char))
break
}
chunk <- gsub("(.*)[,\n][^,\n]*$", "\\1", buffer, perl = TRUE)
buffer <- substr(buffer, nchar(chunk) + 1, nchar(buffer))
cleaned <- gsub(return_pattern, '"\\1"', chunk, perl = TRUE)
writeChar(cleaned, out_conn, eos = NULL)
if (!length(new_chars))
break
}
writeChar('\n', out_conn, eos = NULL)
close(in_conn)
close(out_conn)
result <- fread(output_csv)
过程:
\r
或\n
结尾,则会添加另一个字符,直到它没有。\r
的值
\n
。此代码通过假设sample.csv
中的任何字段都没有引用来简化问题。它不是特别快,但不是非常慢。 chunk_size
的较大值应减少I / O操作所花费的时间。如果用于此玩具示例之外的任何内容,我强烈建议将其包装在tryCatch(...)
调用中,以确保文件在之后关闭。