我正在使用io模塊的輸出流並寫入文件。我希望能夠檢測何時將1G數據寫入文件,然後開始寫入第二個文件。我似乎無法弄清楚如何確定我寫入文件的數據量。如何在使用python寫入文件時限制文件大小
有沒有簡單的內置到io?或者我可能必須在每次手動寫入之前計算字節數?
我正在使用io模塊的輸出流並寫入文件。我希望能夠檢測何時將1G數據寫入文件,然後開始寫入第二個文件。我似乎無法弄清楚如何確定我寫入文件的數據量。如何在使用python寫入文件時限制文件大小
有沒有簡單的內置到io?或者我可能必須在每次手動寫入之前計算字節數?
參見Python文檔爲File Objects,具體tell()。
例子:
>>> f=open('test.txt','w')
>>> f.write(10*'a')
>>> f.tell()
10L
>>> f.write(100*'a')
>>> f.tell()
110L
請參閱流對象上的tell()方法。
我推薦計數。沒有我知道的內部語言計數器。其他人提到使用tell()
,但內部計數器將花費大致相同的工作量並消除常量OS調用。
#pseudocode
if (written + sizeOfNew > 1G) {
rotateFile()
}
如果你正在使用這個文件我建議使用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)
注意:您還甚至可以使用這個方法如果你不使用它進行日誌記錄,如果你喜歡做黑客:)
有關logrotate的信息有助於理解這種方法:http://www.debian-administration.org/articles/117 – 2012-07-13 20:44:50
需要添加:導入日誌記錄。 handlers' – hwang 2013-05-23 21:39:37
一個相當直接的方法是子類的內置file
類並讓它跟蹤寫入文件的輸出量。下面是一些示例代碼,展示了可能如何完成似乎主要工作。
我說的主要是因爲生成的文件的大小有時會略微超過最大值,但是這是因爲測試文件是在「文本」模式下打開的,而在Windows上,這意味着所有'\n'
換行符都會得到轉換爲'\r\n'
(回車,換行)對,這將拋出大小累加器。另外,正如目前所寫,標準file()
和open()
函數接受的參數bufsize
不受支持,因此係統的默認大小和模式將始終使用。
根據你正在做的事情,尺寸問題可能不是什麼大問題 - 但是對於大尺寸的最大尺寸,它可能會明顯偏離。如果任何人有一個良好的平臺獨立的解決方案,通過一切手段讓我們知道。
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()
我注意到你的問題有一個模棱兩可的問題。 (a)在切換之前,(b)在(c)正好大於1GiB的情況下,你想要文件成爲(a)
很容易判斷你是否已經過去了。 tell()
就足夠了那種事情;只需檢查if tell() > 1024*1024*1024:
,你就會知道。
檢查您是否在1GiB以下,但在您下一次寫入時將超過1GiB,是一種類似的技術。 if len(data_to_write) + tell > 1024*1024*1024:
就足夠了。
最棘手的事情就是讓文件準確地達到1GiB。您將需要tell()
文件的長度,然後適當地分割您的數據以便精確地打上標記。
無論您想要哪種語義,tell()
總是會至少和自己計算一樣慢,並且可能會更慢。這並不意味着這是一件錯誤的事情;如果你是從一個線程寫入文件,那麼你幾乎肯定會想要tell()
,而不是希望你已經正確地搶佔了其他線程寫入同一個文件。 (和你的鎖等,但這是另一個問題。)
順便說一句,我注意到你最後幾個問題的明確方向。您是否瞭解Freenode(irc.freenode.net)上的#twisted和#python IRC頻道?你會得到更及時,更有用的答案。
〜C.
只是如果你是明智的使用'告訴()',並允許一些誤差,這比開銷計數少了很多。 – 2010-10-22 17:08:27
我無法想象如何可以少開銷。添加到整數並將其與最大值進行比較都是單指令操作,如果類型有點大,則可以接近它。 tell()正在沿着系統調用樹走。此外,無論何時告訴(),您都在檢查已寫入的內容。你可以在沒有太多麻煩的情況下編寫代碼,但是... – 2010-10-25 13:56:39