如何在编写文件时限制文件大小?

时间:2010-10-22 16:41:13

标签: python file-io

我正在使用io模块的输出流并写入文件。我希望能够检测到何时将1G数据写入文件然后开始写入第二个文件。我似乎无法弄清楚如何确定我写入文件的数据量。

io内置了一些简单的内容吗?或者我可能需要在每次手动写入之前计算字节数?

6 个答案:

答案 0 :(得分:14)

如果您使用此文件进行日志记录,我建议在日志模块中使用RotatingFileHandler,如下所示:

import logging
import logging.handlers

file_name = 'test.log'

test_logger = logging.getLogger('Test')
handler = logging.handlers.RotatingFileHandler(file_name, maxBytes=10**9)
test_logger.addHandler(handler)

N.B:即使您不喜欢使用此方法进行日志记录,也可以使用此方法:)

答案 1 :(得分:9)

请参阅File Objects的Python文档,特别是tell()。

示例:

>>> f=open('test.txt','w')
>>> f.write(10*'a')
>>> f.tell()
10L
>>> f.write(100*'a')
>>> f.tell()
110L

答案 2 :(得分:3)

请参阅流对象上的tell()方法。

答案 3 :(得分:2)

一种相当直接的方法是对内置file类进行子类化,并让它跟踪写入文件的输出量。下面是一些示例代码,展示了如何完成这些工作似乎主要起作用。

我之所以这么说,主要是因为测试时产生的文件大小有时略高于最大值,但那是因为测试文件是在“文本”模式下打开的,而在Windows上这意味着所有'\n'换行符转换为'\r\n'(回车,换行)对,这会抛出大小累加器。此外,如当前所述,不支持标准bufsizefile()函数接受的open()参数,因此将始终使用系统的默认大小和模式。

根据您正在做的事情,尺寸问题可能不是大问题 - 但是对于较大的最大尺寸,它可能会显着偏离。如果有人对此有一个很好的平台无关的解决方案,请务必告诉我们。

import os.path
verbose = False

class LtdSizeFile(file):
    ''' A file subclass which  limits size of file written to approximately "maxsize" bytes '''
    def __init__(self, filename, mode='wt', maxsize=None):
        self.root, self.ext = os.path.splitext(filename)
        self.num = 1
        self.size = 0
        if maxsize is not None and maxsize < 1:
            raise ValueError('"maxsize: argument should be a positive number')
        self.maxsize = maxsize
        file.__init__(self, self._getfilename(), mode)
        if verbose: print 'file "%s" opened' % self._getfilename()

    def close(self):
        file.close(self)
        self.size = 0
        if verbose: print 'file "%s" closed' % self._getfilename()

    def write(self, text):
        lentext =len(text)
        if self.maxsize is None or self.size+lentext <= self.maxsize:
            file.write(self, text)
            self.size += lentext
        else:
            self.close()
            self.num += 1
            file.__init__(self, self._getfilename(), self.mode)
            if verbose: print 'file "%s" opened' % self._getfilename()
            self.num += 1
            file.write(self, text)
            self.size += lentext

    def writelines(self, lines):
        for line in lines:
            self.write(line)

    def _getfilename(self):
        return '{0}{1}{2}'.format(self.root, self.num if self.num > 1 else '', self.ext)

if __name__=='__main__':
    import random
    import string

    def randomword():
        letters = []
        for i in range(random.randrange(2,7)):
            letters.append(random.choice(string.lowercase))
        return ''.join(letters)

    def randomsentence():
        words = []
        for i in range(random.randrange(2,10)):
            words.append(randomword())
        words[0] = words[0].capitalize()
        words[-1] = ''.join([words[-1], '.\n'])
        return ' '.join(words)

    lsfile = LtdSizeFile('LtdSizeTest.txt', 'wt', 100)
    for i in range(100):
        sentence = randomsentence()
        if verbose: print '  writing: {!r}'.format(sentence)
        lsfile.write(sentence)

    lsfile.close()

答案 4 :(得分:1)

我注意到你的问题含糊不清。在切换之前,您是否希望文件(a)在(c)下(c)正好1GiB大?

很容易判断你是否已经过去了。 tell()足以满足这种需要;只需检查if tell() > 1024*1024*1024:,您就会知道。

检查你是否在1GiB以下,但在下一次写入时将超过1GiB,这是一种类似的技巧。 if len(data_to_write) + tell > 1024*1024*1024:就足够了。

最棘手的事情是将文件准确地提供给1GiB。则需要tell()的文件的长度,然后在为了精确地击中标记适当地划分数据。

无论正是你想要的语义,tell()总是将至少为做自己的计数,并可能更慢很慢。这并不意味着做错了;如果你从一个线程写入文件,那么你几乎肯定会想tell(),而不是希望你正确地抢占其他线程写入同一文件。 (做你的锁等等,但这是另一个问题。)

顺便说一句,我注意到你最后几个问题中的明确方向。您是否了解Freenode上的#twisted和#python IRC频道(irc.freenode.net)?您将获得更及时,更有用的答案。

~C。

答案 5 :(得分:0)

我建议数数。我所知道的没有内部语言计数器。有人提到使用tell(),但内部计数器将花费大致相同的工作量并消除不断的OS调用。

#pseudocode
if (written + sizeOfNew > 1G) {
    rotateFile()
}