我想在 python 中构建一个循环文件缓冲区来保存文件名(字符串)。缓冲区应具有以下属性。
- 缓冲区的大小是其名称存储在缓冲区中的文件大小的总和。缓冲区将具有最大允许大小。
- 添加新文件时,如果缓冲区大小小于最大允许大小,则添加该文件名字符串。否则,最旧的修改文件将被推出并添加新文件。如果新添加的文件比缓冲区中已经存在的所有文件都旧,则不会发生任何事情。
是否可以为此目的扩展双端队列?
还是我应该从头开始写?有没有我可以用于此目的的设计理念?
谢谢
肯定的
好的,我相信 Raymond Hettinger 对您的问题的解释是正确的,并且您的评论已经澄清您不关心队列的长度,而是关心所有文件大小的总和。这更有意义,我很高兴我终于明白你的意思了。考虑到这一点,这里有一个简单的实现heapq
,我相信它可以满足您提出的所有要求。通过put
ting(timestamp, filename, filesize)
队列上的元组来使用它,并注意当您get
从队列中取出一个项目时,它将是最旧的文件(即具有最小时间戳的文件。)
import heapq
class FilenameQueue(object):
def __init__(self, times_sizes_names, maxsize):
self.maxsize = maxsize
self.size = sum(s for t, s, n in times_sizes_names)
self.files = list(times_sizes_names)
heapq.heapify(self.files)
while self.size > self.maxsize:
self.get()
def __len__(self):
return len(self.files)
def put(self, time_size_name):
self.size += time_size_name[1]
if self.size < self.maxsize:
heapq.heappush(self.files, time_size_name)
else:
time_size_name = heapq.heappushpop(self.files, time_size_name)
self.size -= time_size_name[1]
def get(self):
time_size_name = heapq.heappop(self.files)
self.size -= time_size_name[1]
return time_size_name
我添加了一个__len__
方法,以便您可以在获取队列之前对其进行测试。这是一个使用示例:
>>> f = FilenameQueue(((22, 33, 'f1'), (44, 55, 'f2'), (33, 22, 'f3')), 150)
>>> while f:
... f.get()
...
(22, 33, 'f1')
(33, 22, 'f3')
(44, 55, 'f2')
>>> f = FilenameQueue(((22, 33, 'f1'), (44, 55, 'f2'), (33, 22, 'f3')), 150)
>>> f.put((55, 66, 'f4'))
>>> while f:
... f.get()
...
(33, 22, 'f3')
(44, 55, 'f2')
(55, 66, 'f4')
请参阅我的编辑历史记录,以了解涉及Queue.PriorityQueue
次优的完全不同的解决方案。我忘记了通过阻止而不是通过丢弃元素来maxsize
强制限制。那不是很有用!
如果我正确阅读了您的问题,则您需要一系列文件名,文件名不超过给定的最大大小。如果添加的新文件超过了最大值,您希望忘记最旧的文件。
这个简单的基于双端队列的类应该很好地处理它:
from collections import deque
class FileDeque(object):
'FIFO queue of files upto a given total size'
def __init__(self, maxsize):
self.maxsize = maxsize
self.d = deque()
self.sizes = dict()
self.currsize = 0
def append(self, filename, filesize):
'Add a new file to the FileDeque'
self.d.append(filename)
self.sizes[filename] = filesize
self.currsize += filesize
while self.currsize > self.maxsize and self.d:
oldfilename = self.d.popleft()
oldfilesize = self.sizes.pop(oldfilename)
self.currsize -= oldfilesize
def __iter__(self):
'List files oldest to newest'
return iter(self.d)
示例会话如下所示:
>>> f = FileDeque(maxsize=10000)
>>> f.append('raptors.txt', 2500)
>>> f.append('rexes.txt', 4200)
>>> list(f)
['raptors.txt', 'rexes.txt']
>>> f.append('stegos.txt', 5000)
>>> list(f)
['rexes.txt', 'stegos.txt']
>>> f.append('brontos.txt', 500)
>>> list(f)
['rexes.txt', 'stegos.txt', 'brontos.txt']
>>> f.append('dactyls.txt', 4000)
>>> list(f)
['stegos.txt', 'brontos.txt', 'dactyls.txt']