在R中将大文件分成小文件

Posted

技术标签:

【中文标题】在R中将大文件分成小文件【英文标题】:Partition a large file into small files in R 【发布时间】:2018-05-13 05:48:35 【问题描述】:

我需要将一个大文件(14 GB)分解成更小的文件。该文件的格式为txt,制表符为“;”我知道它有 70 列(字符串,双精度)。我想读取一百万并将它们保存在不同的文件中,file1,file2 ... fileN。

在@MKR 的帮助下

但是进程很慢,我试过用fread,但是不行。

如何优化这段代码?

新代码

chunkSize <- 10000
conex <- file(description = db, open = "r")
data <- read.table(conex, nrows = chunkSize, header=T, fill=TRUE, sep =";")

index <- 0
counter <- 0
total <- 0
chunkSize <- 500000 
conex <- file(description=db,open="r")   
dataChunk <- read.table(conex, nrows=chunkSize, header=T, fill=TRUE,sep=";")

repeat 
dataChunk <- read.table(conex, nrows=chunkSize, header=FALSE, fill = TRUE, sep=";", col.names=db_colnames)
total <- total + sum(dataChunk$total)
counter <- counter + nrow(dataChunk)
write.table(dataChunk, file = paste0("MY_FILE_new",index),sep=";", row.names = FALSE)

  if (nrow(dataChunk) != chunkSize)
    print('linesok')
    break
    index <- index + 1
  print(paste('lines', index * chunkSize))

【问题讨论】:

【参考方案1】:

您完全在正确的轨道上实现解决方案。

The approach should be:

1. Read 1 million lines 
2. Write to new files
3. Read next 1 million lines
4. Write to another new files

让我们在 OP 的尝试行中循环转换上述逻辑:

index <- 0
counter <- 0
total <- 0
chunks <- 500000

repeat
  dataChunk <- read.table(con, nrows=chunks, header=FALSE, fill = TRUE,                 
                          sep=";", col.names=db_colnames)

  # do processing on dataChunk (i.e adding header, converting data type) 

  # Create a new file name and write to it. You can have your own logic for file names 
  write.table(dataChunk, file = paste0("file",index))

  #check if file end has been reached and break from repeat
  if(nrow(dataChunk) < chunks)
    break
  

  #increment the index to read next chunk
  index = index+1


已编辑:修改为通过 OP 要求的使用 data.table::fread 读取文件来添加另一个选项。

library(data.table)

index <- 0
counter <- 0
total <- 0
chunks <- 1000000
fileName <- "myfile"

repeat
  # With fread file is opened in each iteration
  dataChunk <- fread(input = fileName, nrows=chunks, header=FALSE, fill = TRUE,                 
                          skip = chunks*index, sep=";", col.names=db_colnames)

  # do processing on dataChunk (i.e adding header, converting data type) 

  # Create a new file name and write to it. You can have your own logic for file names
  write.table(dataChunk, file = paste0("file",index))

  #check if file end has been reached and break from repeat
  if(nrow(dataChunk) < chunks)
    break
  

  #increment the index to read next chunk
  index = index+1


注意:以上代码只是pseudo code的部分sn-p帮助OP。它不会自行运行并产生结果。

【讨论】:

@RYoda read.table 有一个参数为skip = ,其中可以指定要跳过的行数,但在这种情况下不需要这样做,因为文件在循环开始之前只打开了一次。因此read.table 将自动从下一行开始。如果文件已关闭并打开,或者 filename 作为参数提供给 read.table,则必须使用 skip 感谢您的帮助@MKR,我已经更改了代码并且它有效,但我想对其进行优化。 @JoyceMaia 很高兴它帮助了你。您可以接受答案,以便将来的用户更容易。我想建议您使用data.table::fread,但对于该功能,您必须维护skip。因此,不要让您感到困惑,让您首先使用一个解决方案。 @JoyceMaia 对不起。刚刚看到您对问题的更新。您已经考虑过使用fread。如果你愿意,我可以帮助你使用它。 fread 多次读取文件速度更快。 改成fread时出现此错误:'input'必须是包含文件名的单个字符串,系统命令至少包含一个空格【参考方案2】:

不是基于 R 的答案,但在这种情况下,我推荐使用 GNU 的 split 的基于 shell 的解决方案。这应该比 R 解决方案快得多。

要将文件拆分为带有10^6 行的块,您可以:

split -l 1000000 my_file.txt 

有关split 的详细信息,请参阅例如here.

【讨论】:

这很酷。但是,我怎样才能“并行”处理所有文件呢? 这个选项很好,效果很好,但是我需要用R来做。很多我不使用的电脑没有Linux,最终问题会再次出现。 @JoyceMaia 关于“并行”处理文件;您将以与在代码中相同的方式处理文件:要么读入文件并以某种形式的循环处理数据,要么使用embarrassingly parallel 方法(例如使用parallel)来读入/处理数据。顺便说一句,GNU 的 CoreUtils(包括 split)是 also available for Windows。

以上是关于在R中将大文件分成小文件的主要内容,如果未能解决你的问题,请参考以下文章

将一个大文件分成若干个小文件方法

Linux下的split 命令(将一个大文件根据行数平均分成若干个小文件)

SqlServer 复制中将大事务分成小事务分发

linux 如何将一个大文件分成几个小文件

怎么样把10万行的大文件分成十分1万行的小文件(Java语言)

如何把一个压缩好的文件,拆分成几个压缩文件?