Одним из довольно простых подходов является создание подкласса встроенного класса 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()