Как ограничить размер файла при записи? - PullRequest
10 голосов
/ 22 октября 2010

Я использую выходные потоки из модуля io и пишу в файлы. Я хочу быть в состоянии определить, когда я записал 1G данных в файл, а затем начать запись во второй файл. Я не могу понять, как определить, сколько данных я записал в файл.

Есть ли что-то простое, встроенное в io? Или мне нужно посчитать байты перед каждой записью вручную?

Ответы [ 6 ]

14 голосов
/ 22 октября 2010

, если вы используете этот файл для целей ведения журнала, я предлагаю использовать 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)

Примечание: вы также можете использовать этот метод, даже если выне используйте это для регистрации, если вам нравится делать хаки:)

9 голосов
/ 22 октября 2010

См. Документацию по Python для Файловых объектов , в частности tell ().

Пример:

>>> f=open('test.txt','w')
>>> f.write(10*'a')
>>> f.tell()
10L
>>> f.write(100*'a')
>>> f.tell()
110L
3 голосов
/ 22 октября 2010

См. Метод tell () для объекта потока.

2 голосов
/ 24 октября 2010

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

Я заметил двусмысленность в вашем вопросе. Вы хотите, чтобы файл был (a) больше (b) меньше (c) ровно 1 ГБ, до переключения?

Легко сказать, перешел ли ты. tell() достаточно для такого рода вещей; просто отметьте if tell() > 1024*1024*1024:, и вы узнаете.

Проверка того, что вы ниже 1 ГБ, но при следующей записи превысит 1 ГБ, является похожей техникой. if len(data_to_write) + tell > 1024*1024*1024: будет достаточно.

Самое хитрое, что нужно сделать, это получить файл с точностью до 1 ГБ. Вам нужно будет tell() длина файла, а затем разделить ваши данные соответствующим образом, чтобы точно попасть в цель.

Независимо от того, какую именно семантику вы хотите, tell() всегда будет по крайней мере столь же медленным, как и сам подсчет, и, возможно, медленнее. Это не значит, что это неправильно. если вы пишете файл из потока, то вы почти наверняка захотите tell(), а не надеетесь, что вы правильно вытеснили другие потоки, записывающие в тот же файл. (И делай свои замки и т. Д., Но это другой вопрос.)

Кстати, я заметил определенное направление в ваших последних двух вопросах. Вам известны IRT-каналы #twisted и #python на Freenode (irc.freenode.net)? Вы получите своевременные, более полезные ответы.

~ C.

0 голосов
/ 22 октября 2010

Рекомендую считать. Там нет внутреннего счетчика языка, о котором я знаю. Кто-то еще упомянул об использовании tell(), но внутренний счетчик займет примерно такой же объем работы и исключит постоянные вызовы ОС.

#pseudocode
if (written + sizeOfNew > 1G) {
    rotateFile()
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...