我正在使用io模块的输出流并写入文件。我希望能够检测到何时将1G数据写入文件然后开始写入第二个文件。我似乎无法弄清楚如何确定我写入文件的数据量。
io
内置了一些简单的内容吗?或者我可能需要在每次手动写入之前计算字节数?
答案 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'
(回车,换行)对,这会抛出大小累加器。此外,如当前所述,不支持标准bufsize
和file()
函数接受的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()
}