将文本文件拆分为较小的文件

时间:2018-12-16 07:29:06

标签: python python-3.x split text-files

我正在尝试在Python 3中找到一种方法,该方法将接受作为输入提供的任何文件,并从原始文件创建4个较小的文件。就字符数而言,四个较小的文件的长度必须彼此相似。如果无法根据文本文件中的字符数执行此操作,是否可以按字节将其拆分,但是如果文本文件的大小更改,它仍然可以工作吗?

作为测试文件,我只是重复使用了几次字母。这完全按照需要工作。在具有多台服务器的对等文件共享系统中使用此功能。给定的文件应该分成4个较小的文件,每个文件都将放置在两个服务器上,这样,如果出现任何问题,仍然可以进行备份。

2 个答案:

答案 0 :(得分:1)

(在2018年)文本文件通常经过UTF-8编码。请注意,许多人不会说英语或说英语,可能会使用其他人类语言和“字符”(包括smileys)。阅读utf8everywhere.org了解更多。而且,如果它不是UTF-8编码的,则您需要了解(通过其他方式)或决定使用确切的character encoding

在UTF-8中,许多Unicode字符(例如§éЖλאح等...)需要几个字节进行编码。因此,您不能在任意字节边界处分割UTF-8编码的文本文件,而应在unicode字符的末尾分割它。

  

作为测试文件,我只是重复使用几次字母

那太天真了。您应该使用还包含奇怪字符(例如希腊语,阿拉伯语,西里尔字母,汉字或或笑脸等数学符号)的文件来测试解决方案,而不仅仅是英语字母。< / p>

  

是否可以按字节分解

否,如果它是UTF-8编码的(因为正如我所解释,原始文件的某些Unicode字符可能需要几个字节)。如果您将一个Unicode字符拆分为“在中间”几个字节,则结果通常不符合UTF-8(例如é是由两个字节 0xc3 0xa9 以十六进制表示,但 0xc3 不会 not 编码 valid UTF-隔离8个字符)

  

但是如果文本文件的大小更改了,它仍然可以工作吗?

如果原始源文件发生更改,则需要再次对其进行处理,以将其再次分成较小的块。如何检测原始源文件何时已更改是另一个问题(在Linux上,在某些情况下,您可能使用inotify(7)工具来检测此类更改)。许多operating systemsfile systems保留修改时间(例如POSIX系统上st_mtime赋予的stat(2)),您可以使用它来触发拆分。当然,详细信息是操作系统专用

您可能希望将文本文件分成整条的块(因此不要在任意字节边界)。为此,您可以在Linux上使用split(1)(可以在Linux上使用wc(1)-l来计算行数)。

当然,您可以轻松地在Python中编写一个函数,该函数计算文本文件中的行数,而另一个函数则将其分成整行,因为Python具有便利性(例如,{{readline}函数{3}})来阅读整行。或者,您可以像io一样,将文件拆分成大约相等的字符长度的块,这不是不是个字节的长度(正如您的问题明确要求的:“按字节分解”) )。

答案 1 :(得分:0)

我认为通过字符计数是可行的(在UTF-8编码中,一个字符可能会占用一个以上的字节)。我们可以将其分解为两个问题:

  • 首先-计算文件中的字符数。
  • 第二个-根据字符数将文件拆分为多个段。 下面是一个幼稚的解决方案。

我已经在下面的简单ASCII文件和UTF-8示例文件中测试了以下代码:https://www.w3.org/2001/06/utf-8-test/UTF-8-demo.html

文本文件的一个小示例将帮助人们了解您的问题。

天真解决方案

编辑:添加了逻辑以处理字符计数不能被拆分/段计数整除的情况。

import os

def split_file(in_file_name, split_count):
    """Splits the input file into a specified number of segments."""
    with open(in_file_name, 'r') as in_file:
        # Get a count of characters in the file.
        character_count = 0
        for line in in_file:  
            for character in line: 
                character_count = character_count + 1
        size_per_out_file = character_count / split_count

        # Split up the input file into chunks/segments.
        in_file.seek(0)
        for i in range(0, split_count):
            if (i == (split_count - 1)):
                current_out_content = in_file.read(size_per_out_file + split_count)
            else:
                current_out_content = in_file.read(size_per_out_file)
            out_file_name = '%s_segment_%d.txt' % (in_file_name, i)
            with open(out_file_name, 'w') as current_out_file:
                current_out_file.write(current_out_content)

if __name__ == "__main__":
    split_file("in_file.txt", 4)