StringIO
存在的意义
比如想写一个脚本, 从网站下载一个压缩文件, 并解压到本地. 下意识可能分为三部
- 下载文件
- 写入到本地
- 用zipfile读取这个文件并解压
代码如下:
# 1. 下载
import urllib2
res = urllib.openurl(url)
zip_data = res.read()
# 2. 写入本地
with open(file_name_zip, 'wb') as f:
f.write(zip_data)
# 3. 解压
target_dir = r'C:\test'
zip_file = zipfile.ZipFile(file_name_zip)
zip_list = zip_file.namelist()
for f in zip_list:
zip_file.extract(f, target_dir)
zip_file.close()
这样其实有一个很大的问题, 下载很快, 解压很快, 但是写入到本地很慢.
仔细看zipfile会发现(如下图): zipfile也是需要读取本地文件, 那为什么我们不能不写入本地, 而直接把数据传递进去呢?
查看官方文档, 会发现, zipfile只需要传入一个file-like的类
即可, 也就是说只需要一个有read()方法的类
, 返回数据就行, 但是这样做了会发现, zipfile
中不仅使用了read
, 也使用了seek
, 那么我们自己构建这个类就非常麻烦了.
这个时候. StringIO
就出现了, 它只需要把数据传进去, 然后你就能以类似文件操作的方式去使用它, read
, seek
等文件类型的操作, 里面都是存在的, 唯一需要操作的就是把数据传进去.
那么我们上面那段代码就会变成下面这样
# 1. 下载
import urllib2
res = urllib.openurl(url)
zip_data = res.read()
# 2. 构建stringio
from StringIO import StringIO
string_io_file = StringIO(zip_data)
# 3. 解压
target_dir = r'C:\test'
# 直接把stringio类传进去
zip_file = zipfile.ZipFile(string_io_file)
zip_list = zip_file.namelist()
for f in zip_list:
zip_file.extract(f, target_dir)
zip_file.close()
这样我们就省去了写的操作, 别小看这一步, 最起码提升效率1倍以上, 特别是当你网速比较快的时候, 卡住的其实就是写操作, 省去了这一步, 效率就会明显提升.