Ruby:如何将文件拆分为给定大小的多个文件

maa*_*sha 7 ruby size split file

我想将一个txt文件拆分成多个文件,其中每个文件包含不超过5Mb.我知道有这方面的工具,但我需要这个项目,并希望在Ruby中做到这一点.另外,如果可能的话,我更喜欢在块上下文中使用File.open执行此操作,但我失败了:o(

#!/usr/bin/env ruby

require 'pp'

MAX_BYTES = 5_000_000

file_num = 0
bytes    = 0

File.open("test.txt", 'r') do |data_in|
  File.open("#{file_num}.txt", 'w') do |data_out|
    data_in.each_line do |line|
      data_out.puts line

      bytes += line.length

      if bytes > MAX_BYTES
        bytes = 0
        file_num += 1
        # next file
      end
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

这项工作,但我认为它不优雅.此外,我仍然想知道是否可以在块上下文中使用File.open完成.

#!/usr/bin/env ruby

require 'pp'

MAX_BYTES = 5_000_000

file_num = 0
bytes    = 0

File.open("test.txt", 'r') do |data_in|
  data_out = File.open("#{file_num}.txt", 'w')

  data_in.each_line do |line|
    data_out = File.open("#{file_num}.txt", 'w') unless data_out.respond_to? :write
    data_out.puts line

    bytes += line.length

    if bytes > MAX_BYTES
      bytes = 0
      file_num += 1
      data_out.close
    end
  end

  data_out.close if data_out.respond_to? :close
end
Run Code Online (Sandbox Code Playgroud)

干杯,

马丁

asa*_*aki 17

[更新]写了一个没有任何辅助变量的简短版本,并将所有内容放在一个方法中:

def chunker f_in, out_pref, chunksize = 1_073_741_824
  File.open(f_in,"r") do |fh_in|
    until fh_in.eof?
      File.open("#{out_pref}_#{"%05d"%(fh_in.pos/chunksize)}.txt","w") do |fh_out|
        fh_out << fh_in.read(chunksize)
      end
    end
  end
end

chunker "inputfile.txt", "output_prefix" (, desired_chunk_size)
Run Code Online (Sandbox Code Playgroud)

您可以使用.read(length)并仅为EOF标记和文件光标执行循环,而不是行循环.

这使得粗块文件永远不会超过您想要的块大小.

另一方面,它永远不会关注换行符(\n)!

块文件的编号将通过chunksize从当前文件光标位置的整数除法生成,格式为"%05d",导致带有前导零(00001)的5位数字.

这是唯一可行的,因为.read(chunksize)使用.在下面的第二个例子中,它无法使用!

更新: 使用换行符识别拆分

如果你真的需要完整的行,\n那么使用这个修改过的代码片段:

def chunker f_in, out_pref, chunksize = 1_073_741_824
  outfilenum = 1
  File.open(f_in,"r") do |fh_in|
    until fh_in.eof?
      File.open("#{out_pref}_#{outfilenum}.txt","w") do |fh_out|
        line = ""
        while fh_out.size <= (chunksize-line.length) && !fh_in.eof?
          line = fh_in.readline
          fh_out << line
        end
      end
      outfilenum += 1
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

我已经向大家介绍一个辅助变量line,因为我想确保矮胖文件大小总是低于chunksize极限!如果您不进行此扩展检查,您将获得超出限制的文件大小.该while语句仅在已经写入行时成功检查下一个迭代步骤.(使用.ungetc或其他复杂的计算将使代码更难以阅读并且不会比此示例更短.)

不幸的是,您必须进行第二次EOF检查,因为最后一次块迭代将主要导致较小的块.

还需要两个辅助变量:line如上所述,outfilenum需要这样做,因为生成的文件大小大多与精确不匹配chunksize.


Way*_*rad 12

对于任何大小的文件,split将比临时构建的Ruby代码更快,甚至考虑到启动单独的可执行文件的成本.它也是您不必编写,调试或维护的代码:

system("split -C 1M -d test.txt ''")
Run Code Online (Sandbox Code Playgroud)

选项是:

  • -C 1M 在每个块中放置总计不超过1M的行
  • -d 在输出文件名中使用十进制后缀
  • test.txt 输入文件的名称
  • '' 使用空白输出文件前缀

除非你在Windows上,否则这就是你要走的路.