使用python拆分大文件

使用python拆分大文件,python,split,Python,Split,我在尝试拆分大文件时遇到了一些问题(例如,大约10GB)。基本思想是简单地读取行,并将每行(比如40000行)分组到一个文件中。 但是有两种“读取”文件的方法 1) 第一种方法是一次读取整个文件,并将其列成一个列表。但这需要将整个文件加载到内存中,这对于太大的文件来说是痛苦的。(我想我以前问过这样的问题) 在python中,我尝试过的一次读取整个文件的方法包括: input1=f.readlines() input1 = commands.getoutput('zcat ' + file).s

我在尝试拆分大文件时遇到了一些问题(例如,大约10GB)。基本思想是简单地读取行,并将每行(比如40000行)分组到一个文件中。 但是有两种“读取”文件的方法

1) 第一种方法是一次读取整个文件,并将其列成一个列表。但这需要将整个文件加载到内存中,这对于太大的文件来说是痛苦的。(我想我以前问过这样的问题) 在python中,我尝试过的一次读取整个文件的方法包括:

input1=f.readlines()

input1 = commands.getoutput('zcat ' + file).splitlines(True)

input1 = subprocess.Popen(["cat",file],
                              stdout=subprocess.PIPE,bufsize=1)
那么,我就可以通过:
list[4000080000]或list[80000120000]轻松地将40000行分组到一个文件中。
或者使用列表的优点是,我们可以很容易地指向特定的行

2) 第二种方法是逐行阅读;在阅读时处理该行。那些读取的行不会保存在内存中。 例子包括:

f=gzip.open(file)
for line in f: blablabla...

我确信对于gzip.open,这个f不是一个列表,而是一个文件对象。似乎我们只能一行一行地处理;那么我如何执行这个“拆分”作业?如何指向文件对象的特定行


感谢提供10GB文件,第二种方法显然是可行的。以下是您需要做的事情的概要:

  • 打开输入文件
  • 打开第一个输出文件
  • 从输入文件中读取一行并将其写入输出文件
  • 记录写入当前输出文件的行数;当它达到40000时,关闭输出文件,然后打开下一个文件
  • 重复步骤3-4,直到到达输入文件的末尾
  • 关闭两个文件

  • 如果在每个文件中具有特定数量的文件行没有什么特别之处,则还接受一个大小“提示”参数,其行为如下:

    # assume that an average line is about 80 chars long, and that we want about 
    # 40K in each file.
    
    SIZE_HINT = 80 * 40000
    
    fileNumber = 0
    with open("inputFile.txt", "rt") as f:
       while True:
          buf = f.readlines(SIZE_HINT)
          if not buf:
             # we've read the entire file in, so we're done.
             break
          outFile = open("outFile%d.txt" % fileNumber, "wt")
          outFile.write(buf)
          outFile.close()
          fileNumber += 1 
    
    如果给定一个可选参数sizehint,它将从 文件和足够多的内容来完成一行,并返回这些行 从那以后。这通常用于有效读取大型数据 逐行归档,但不必将整个文件加载到内存中。 只返回完整的行

    …因此您可以编写如下代码:

    # assume that an average line is about 80 chars long, and that we want about 
    # 40K in each file.
    
    SIZE_HINT = 80 * 40000
    
    fileNumber = 0
    with open("inputFile.txt", "rt") as f:
       while True:
          buf = f.readlines(SIZE_HINT)
          if not buf:
             # we've read the entire file in, so we're done.
             break
          outFile = open("outFile%d.txt" % fileNumber, "wt")
          outFile.write(buf)
          outFile.close()
          fileNumber += 1 
    

    显然,在处理文件时,需要以某种方式对文件内容进行迭代——不管是手动执行还是让Python API的一部分(例如readlines()方法)为您执行,都不重要。在大O分析中,这意味着您将花费O(n)时间(n是文件的大小)

    但是将文件读入内存也需要O(n)空间。虽然有时我们确实需要将10 gb的文件读入内存,但您的特定问题并不需要这样做。我们可以直接迭代file对象。当然,file对象确实需要空间,但我们没有理由以两种不同的形式保存文件内容两次


    因此,我将使用您的第二个解决方案。

    我找到的最佳解决方案是使用库filesplit()。
    您只需要指定输入文件、输出文件夹以及输出文件所需的字节大小。最后,图书馆将为您完成所有工作

    from fsplit.filesplit import Filesplit
    fs = Filesplit()
    def split_cb(f, s):
        print("file: {0}, size: {1}".format(f, s))
    
    fs.split(file="/path/to/source/file", split_size=900000, output_dir="/pathto/output/dir", callback=split_cb)
    

    当你想起来的时候。。你不能。只有在阅读了前面的所有行并计算了换行次数(\n)之后,才能知道您在哪一行。(忽略特殊情况,即这是一个奇怪的文件,其中每行的长度都是已知的。)如果您希望文件中正好有40000行,我认为您应该将
    I
    初始化为
    0
    ,而不是
    1
    。您需要什么软件包?@LuisFelipe不需要外部软件包,
    fileinput
    是一个内置软件包,此功能甚至不需要它,您也可以使用普通的
    open()
    我尝试了相同的代码,它说“name'filename'未定义”@LuisFelipe
    filename
    是一个变量,它应该包含输入文件的路径
    如果num\u行%4000==0:避免在结尾处写入空文件(),除非numlines==0
    您需要执行
    如果fout:fout.close()
    退出循环后-1(1)您没有显式关闭输出文件(2)在文本模式下阅读,在二进制模式下写作,保证“如果我们在windows上的话,就可以大吃一惊”
    # assume that an average line is about 80 chars long, and that we want about 
    # 40K in each file.
    
    SIZE_HINT = 80 * 40000
    
    fileNumber = 0
    with open("inputFile.txt", "rt") as f:
       while True:
          buf = f.readlines(SIZE_HINT)
          if not buf:
             # we've read the entire file in, so we're done.
             break
          outFile = open("outFile%d.txt" % fileNumber, "wt")
          outFile.write(buf)
          outFile.close()
          fileNumber += 1 
    
    from fsplit.filesplit import Filesplit
    fs = Filesplit()
    def split_cb(f, s):
        print("file: {0}, size: {1}".format(f, s))
    
    fs.split(file="/path/to/source/file", split_size=900000, output_dir="/pathto/output/dir", callback=split_cb)