05- 实现磁盘缓存
[toc]
3.3.1 实现磁盘缓存
上一节中,我们介绍了创建基于磁盘的缓存时需要考虑的文件系统限制,包括允许使用哪些字符、文件名长度限制,以及确保文件和目录的创建位置不同。把URL到文件名的这些映射逻辑与代码结合起来,就形成了磁盘缓存的主要部分。下面是 DiskCache 类的初始实现代码。
import os
import re
from urllib.parse import urlsplit
class DiskCache:
def __init__(self, cache_dir='cache', max_len=255):
self.cache_dir = cache_dir
self.max_len = max_len
def url_to_path(self, url):
""" Return file system path string for given URL"""
components = urlsplit(url)
# append index.html to empty paths
path = components.path
if not path:
path = '/index.html'
elif path.endswith('/'):
path += 'index.html'
filename = components.netloc + path + components.query
# replace invalid characters
filename = re.sub('[^/0-9a-zA-Z\-.,;_ ]', '_', filename)
# restrict maximum number of characters
filename = '/'.join(seg[:self.max_len] for seg in
filename.split('/'))
return os.path.join(self.cache_dir, filename)
在上面的代码中,构造方法传入了一个用于设定缓存位置的参数,然后在 url_to_path 方法中应用了前面讨论的文件名限制。现在,我们还缺少根据文件名存取数据的方法。
下面的代码实现了这两个缺失的方法。
import json
class DiskCache:
...
def __getitem__(self, url):
"""Load data from disk for given URL"""
path = self.url_to_path(url)
if os.path.exists(path):
return json.load(path)
else:
# URL has not yet been cached
raise KeyError(url + ' does not exist')
def __setitem__(self, url, result):
"""Save data to disk for given url"""
path = self.url_to_path(url)
folder = os.path.dirname(path)
if not os.path.exists(folder):
os.makedirs(folder)
json.dump(result, path)
在 __setitem()__ 中,我们使用 url_to_path() 方法将URL映射为安全文件名,在必要情况下还需要创建父目录。这里使用的 json 模块会对Python进行序列化处理,然后保存到磁盘中。而在 __getitem__() 方法中,首先会将URL映射为安全文件名。如果文件存在,则使用 json 加载其内容,并恢复其原始数据类型;如果文件不存在(即缓存中还没有该URL的数据),则会抛出 KeyError 异常。