首页 > 解决方案 > 在 R 中将二进制文件分成更小的部分

问题描述

我有几个大文件,我想将它们转换成二进制文件。一旦它是二进制的,我想让每块小于 5GB。因此,无论有多少,都作为 R 中的对象存在。

我不确定从哪里开始,但通常我是通过伪代码。

file <- ***FILE PATH****

binFile <- writeBin(file,con)

# loop through length of 'binFile' until file.size() = 5000000 then write to a list, continue with the rest and repeat til the whole file is complete.

#Then each item in the list can be called.

如果更容易将它们作为更小的二进制文件写入我的本地也可以工作。

标签: rbinary

解决方案


您可以将一个大文件拆分为多个块,而无需将整个文件加载到内存中。这是一个可以做到这一点的函数。

你向它提供你的大文件的路径,你想要保存块的目录的路径,以及最大的块大小。

文件将全部以大文件的名称加上块号和文件类型保存.bin

原始文件保持不变。

如果您想将块作为二进制文件读入 R,您可以使用readBin

chop_file <- function(bigfile, save_path, chunk_size)
{
  con <- file(bigfile, "rb")
  pos <- 0
  file_size <- file.size(bigfile)
  chunk_no <- 1
  filenames <- sapply(strsplit(bigfile, "/"), function(x) x[length(x)])
  filenames <- gsub("[.]", "", filenames)

  while(pos < file_size)
  {
    seek(con, pos)
    data <- readBin(con, "raw", chunk_size)
    pos  <- seek(con, 0)
    writeBin(data, paste0(save_path, filenames, chunk_no, ".bin"))
    chunk_no <- chunk_no + 1
  }

  close(con)
  message(paste("  File", bigfile, "split into", chunk_no - 1, "chunks"))
}

例如,如果我在以下目录中有一个大型二进制文件:

dir("C:/Users/Me/pdfs/")
# [1] bigfile.pdf

我希望在空目录中将它分成 1MB 块C:/Users/Me/chunks/,我这样做:

chop_file("C:/Users/Me/pdfs/bigfile.pdf", "C:/Users/Me/chunks/", 1e6)
#>  File C:/Users/Me/pdfs/bigfile.pdf split into 10 chunks

现在

dir("C:/Users/Me/chunks/")
#> [1] "bigfilepdf1.bin"  "bigfilepdf2.bin"  "bigfilepdf3.bin"  "bigfilepdf4.bin" 
#> [5] "bigfilepdf5.bin"  "bigfilepdf6.bin"  "bigfilepdf7.bin"  "bigfilepdf8.bin" 
#> [9] "bigfilepdf9.bin"  "bigfilepdf10.bin"

如果您想在内存中将所有这些重新缝合在一起,您可以这样做:

data <- list()
files <- dir("C:/Users/Me/chunks/")
for(i in seq_along(files)) data[[i]] <- readBin(files[i], "raw", 10e6)
data <- do.call("c", data)

然后data将包含原始文件的所有字节作为原始向量。

identical(data, readBin("C:/Users/Me/pdfs/bigfile.pdf", "raw", 1e7))
#> [1] TRUE

如果您希望在内存中处理块而不是将它们写入磁盘,则可以稍微简化一下:

chop_file_to_list <- function(bigfile, chunk_size)
{
  con <- file(bigfile, "rb")
  pos <- 0
  file_size <- file.size(bigfile)
  chunk_no <- 1
  data <- list()

  while(pos < file_size)
  {
    seek(con, pos)
    data[[chunk_no]] <- readBin(con, "raw", chunk_size)
    pos  <- seek(con, 0)
    chunk_no <- chunk_no + 1
  }

  close(con)
  return(data)
}

推荐阅读