我有一个平面文件,固定宽度既没有换行也没有换行(从AS400转储)。
如何将此文件加载到R data.frame?
我尝试过textConnection和read.fwf的不同组合,但没有用。
下面的代码崩溃了Rstudio,所以我假设我正在超载系统。
下面的 len
是24376400,这对于我通常使用read.table加载的文件来说是驯服的。
记录长度为400.
我应该设置任何RECLEN参数,类似于SAS吗? 是否有设置EOL =“\ n”或“\ r \ n”的选项?谢谢。
fname <- "AS400FILE.TXT"
len <- file.info(fname)$size
conn <- file(fname, 'r')
contents <- readChar(conn, len)
close(conn)
df <- read.fwf( textConnection(contents) , widths=layout$length , sep="")
> dput(layout)
structure(list(start = c(1L, 41L, 81L, 121L, 161L, 201L, 224L,
226L, 231L, 235L, 237L, 238L, 240L, 280L, 290L, 300L, 305L, 308L,
309L, 330L, 335L, 337L, 349L, 350L, 351L, 355L, 365L), end = c(40L,
80L, 120L, 160L, 200L, 223L, 225L, 230L, 234L, 236L, 237L, 239L,
279L, 289L, 299L, 304L, 307L, 308L, 329L, 334L, 336L, 348L, 349L,
350L, 354L, 364L, 400L), length = c(40L, 40L, 40L, 40L, 40L,
23L, 2L, 5L, 4L, 2L, 1L, 2L, 40L, 10L, 10L, 5L, 3L, 1L, 21L,
5L, 2L, 12L, 1L, 1L, 4L, 10L, 36L), label = c("TITLE", "SUFFIX",
"ADDRESS1", "ADDRESS2", "ADDRESS3", "CITY", "STATE",
"ZIP", "ZIP+4", "DELIVERY", "CHECKD", "FILLER", "NAME",
"SOURCECODE", "ID", "FILLER", "BATCH", "FILLER", "FILLER",
"GRID", "LOT", "FILLER", "CONTROL",
"ZIPIND", "TROUTE", "SOURCEA", "FILLER")), .Names = c("start",
"end", "length", "label"), class = "data.frame", row.names = c(NA,
-27L))
> dim(layout)
[1] 27 4
>
答案 0 :(得分:3)
您可以使用readChar
。
首先编写一些示例数据(我认为格式就像我从问题中所描述的那样描述?即每列指定宽度的文本墙,整个文件中没有新行):
lengths <- c(2,3,4,2,3,4)
nFields <- length(lengths)
nRows <- 10 # let's make 10 rows.
contents <- paste(letters[sample.int(26,size=sum(lengths)*nRows,replace=TRUE)],
collapse="")
#> contents
#[1] "lepajmcgcqooekmedjprkmmicm.......
cat(contents,file='test.txt')
我可以想到3种方法,每种方法之间存在各种差异:
如果你事先知道行数,你可以这样做:
# If you know #rows in advance..
conn <- file('test.txt','r')
data <- readChar( conn, rep(lengths,nRows) )
close(conn)
# reshape data to dataframe
df <- data.frame(matrix(data,ncol=nFields,byrow=T))
否则你可以使用循环(为什么在文件中读取一次以计算出行数然后再解析?)
# Otherwise use a loop
conn <- file('test.txt','r')
df <- data.frame(matrix(nrow=0,ncol=6)) # initialise 0-row data frame
while ( length(data <- readChar(conn, lengths)) > 0 ) {
df[nrow(df)+1,] <- data
}
close(conn)
或者,由于您已经在字符串中包含了所有contents
,因此您只需使用substring
拆分字符串:
# have already read in contents so can calculate nRows
nRows <- floor(nchar(contents)/sum(lengths)) # 10 for my example
starts <- c(0,cumsum(lengths[-nFields]))
df3 <- data.frame(t(
vapply( seq(1,nRows*sum(lengths),sum(lengths)),
function(r)
substring(contents,starts+r,starts+r+lengths-1),
rep("",nFields) )))
如果你想在尽可能少的文件读取中进行,我建议使用第二种或第三种方法。
第三种方法对我来说“感觉”最优雅,但要求您同时阅读整个contents
,这取决于文件大小,可能不可行。
如果是这种情况,我会选择第二种,一次只读取一组nFields
个字段。
我不推荐第一个,除非提前知道行数 - 这只是我的第一次尝试。我不推荐它,因为您必须首先读入文件以确定行数,然后关闭它并再次在中读取。如果你想沿着这条路走下去,那就去使用方法3吧!但是,如果您事先通过其他方式知道行数,则可以使用此方法。