configparser 从 zip 加载配置文件
configparser loading config files from zip
我正在创建一个从压缩文件加载和运行 python 脚本的程序。除了那些 python 脚本,我还有一个配置文件,我以前使用 configparser 从程序的未压缩版本中加载信息。
是否可以直接用configparser直接读取zip文件中的配置文件?还是我必须将其解压缩到一个临时文件夹中并从那里加载它?
我试过直接给出路径:
>>> sysconf = configparser.ConfigParser()
>>> sysconf.read_file("compressed.zip/config_data.conf")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.4/configparser.py", line 691, in read_file
self._read(f, source)
File "/usr/local/lib/python3.4/configparser.py", line 1058, in _read
raise MissingSectionHeaderError(fpname, lineno, line)
configparser.MissingSectionHeaderError: File contains no section headers.
file: '<???>', line: 1
没用。没有惊喜。
然后我尝试使用 zipfile
>>> zf = zipfile.ZipFile("compressed.zip")
>>> data = zf.read("config_data.conf")
>>> sysconf = configparser.ConfigParser()
>>> sysconf.read_file(data)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.4/configparser.py", line 691, in read_file
self._read(f, source)
File "/usr/local/lib/python3.4/configparser.py", line 1009, in _read
if line.strip().startswith(prefix):
AttributeError: 'int' object has no attribute 'strip'
发现也没用
所以我求助于创建一个临时文件夹,解压缩到它,然后读取那里的 conf 文件。如果可能的话,我真的很想避免这种情况,因为 conf 文件是唯一的限制因素。此时我可以(并且正在)从 zip 文件加载 python 模块。
如果有办法将文件的原始文本直接传递给 configparser,我可以获得文件的原始文本,但搜索文档时我空手而归。
更新:
我尝试使用 stringIO 作为文件对象,它似乎有点工作。
configparser不拒绝,但也不喜欢
>>> zf = zipfile.ZipFile("compressed.zip")
>>> data = zf.read(config_data.conf)
>>> confdata = io.StringIO(str(data))
>>> sysconf = configparser.ConfigParser()
>>> sysconf.readfp(confdata)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.4/configparser.py", line 736, in readfp
self.read_file(fp, source=filename)
File "/usr/local/lib/python3.4/configparser.py", line 691, in read_file
self._read(f, source)
File "/usr/local/lib/python3.4/configparser.py", line 1058, in _read
raise MissingSectionHeaderError(fpname, lineno, line)
configparser.MissingSectionHeaderError: File contains no section headers.
file: '<???>', line: 1
(continues to spit out the entire contents of the file)
如果我改用 read_file,它不会出错,但也不会加载任何内容。
>>> zf = zipfile.ZipFile("compressed.zip")
>>> data = zf.read(config_data.conf)
>>> confdata = io.StringIO(str(data))
>>> sysconf = configparser.ConfigParser()
>>> sysconf.read_file(confdata)
>>> sysconf.items("General") #(this is the main section in the file)
Traceback (most recent call last):
File "/usr/local/lib/python3.4/configparser.py", line 824, in items
d.update(self._sections[section])
KeyError: 'General'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.4/configparser.py", line 827, in items
raise NoSectionError(section)
configparser.NoSectionError: No section: 'General'
can get the raw text of the file if there's a way to pass that directly to configparser
尝试configparser.ConfigParser.read_string
当加上适当的 ZIP 文件时,这段代码对我有用:
import zipfile
import configparser
zf = zipfile.ZipFile("compressed.zip")
zf_config = zf.open("config_data.conf", "rU")
zf_config_data = zf_config.read().decode('ascii')
config = configparser.ConfigParser()
config.read_string(zf_config_data)
assert config['today']['lunch']=='cheeseburger'
经过思考,以下可能更合适:
import zipfile
import configparser
import io
zf = zipfile.ZipFile("compressed.zip")
zf_config = zf.open("config_data.conf", "rU")
zf_config = io.TextIOWrapper(zf_config)
config = configparser.ConfigParser()
config.read_file(zf_config)
assert config['today']['lunch']=='cheeseburger'
ZipFile
不仅支持read
还支持open
,其中returns是类文件对象。所以,你可以这样做:
zf = zipfile.ZipFile("compressed.zip")
config_file = zf.open("config_data.conf")
sysconfig = configparser.ConfigParser()
sysconfig.readfp(config_file)
如评论中所写,@matthewatabet 的回答不适用于 Python 3.4(和更新版本)。这是因为 ZipFile.open
现在 returns 是一个“类似字节”的对象,不再是“类似文件”的对象。您可以使用:
codecs.getreader("utf-8")(config_file)
使用 UTF-8 编码将 config_file
类字节对象转换为类文件对象。现在的代码是:
import zipfile, configparser, codecs
# Python >= 3.4
with zipfile.ZipFile("compressed.zip") as zf:
config_file = zf.open("config_data.conf") # binary mode
sysconfig = configparser.ConfigParser()
sysconfig.read_file(codecs.getreader("utf-8")(config_file))
这似乎比创建string
更令人满意,但我不知道它是否更有效率...
EDIT 从 Python 3.9 开始,zipfile
模块提供了一个可以处理文本和二进制模式的 zipfile.Path.open
method。默认为文本模式。以下代码工作正常:
# Python >= 3.9
with zipfile.ZipFile("compressed.zip") as zf:
zip_path = zipfile.Path(zf)
config_path = zip_path / "config_data.conf"
config_file = config_path.open() # text mode
sysconfig = configparser.ConfigParser()
sysconfig.read_file(config_file)
我正在创建一个从压缩文件加载和运行 python 脚本的程序。除了那些 python 脚本,我还有一个配置文件,我以前使用 configparser 从程序的未压缩版本中加载信息。
是否可以直接用configparser直接读取zip文件中的配置文件?还是我必须将其解压缩到一个临时文件夹中并从那里加载它?
我试过直接给出路径:
>>> sysconf = configparser.ConfigParser()
>>> sysconf.read_file("compressed.zip/config_data.conf")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.4/configparser.py", line 691, in read_file
self._read(f, source)
File "/usr/local/lib/python3.4/configparser.py", line 1058, in _read
raise MissingSectionHeaderError(fpname, lineno, line)
configparser.MissingSectionHeaderError: File contains no section headers.
file: '<???>', line: 1
没用。没有惊喜。
然后我尝试使用 zipfile
>>> zf = zipfile.ZipFile("compressed.zip")
>>> data = zf.read("config_data.conf")
>>> sysconf = configparser.ConfigParser()
>>> sysconf.read_file(data)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.4/configparser.py", line 691, in read_file
self._read(f, source)
File "/usr/local/lib/python3.4/configparser.py", line 1009, in _read
if line.strip().startswith(prefix):
AttributeError: 'int' object has no attribute 'strip'
发现也没用
所以我求助于创建一个临时文件夹,解压缩到它,然后读取那里的 conf 文件。如果可能的话,我真的很想避免这种情况,因为 conf 文件是唯一的限制因素。此时我可以(并且正在)从 zip 文件加载 python 模块。
如果有办法将文件的原始文本直接传递给 configparser,我可以获得文件的原始文本,但搜索文档时我空手而归。
更新: 我尝试使用 stringIO 作为文件对象,它似乎有点工作。 configparser不拒绝,但也不喜欢
>>> zf = zipfile.ZipFile("compressed.zip")
>>> data = zf.read(config_data.conf)
>>> confdata = io.StringIO(str(data))
>>> sysconf = configparser.ConfigParser()
>>> sysconf.readfp(confdata)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.4/configparser.py", line 736, in readfp
self.read_file(fp, source=filename)
File "/usr/local/lib/python3.4/configparser.py", line 691, in read_file
self._read(f, source)
File "/usr/local/lib/python3.4/configparser.py", line 1058, in _read
raise MissingSectionHeaderError(fpname, lineno, line)
configparser.MissingSectionHeaderError: File contains no section headers.
file: '<???>', line: 1
(continues to spit out the entire contents of the file)
如果我改用 read_file,它不会出错,但也不会加载任何内容。
>>> zf = zipfile.ZipFile("compressed.zip")
>>> data = zf.read(config_data.conf)
>>> confdata = io.StringIO(str(data))
>>> sysconf = configparser.ConfigParser()
>>> sysconf.read_file(confdata)
>>> sysconf.items("General") #(this is the main section in the file)
Traceback (most recent call last):
File "/usr/local/lib/python3.4/configparser.py", line 824, in items
d.update(self._sections[section])
KeyError: 'General'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.4/configparser.py", line 827, in items
raise NoSectionError(section)
configparser.NoSectionError: No section: 'General'
can get the raw text of the file if there's a way to pass that directly to configparser
尝试configparser.ConfigParser.read_string
当加上适当的 ZIP 文件时,这段代码对我有用:
import zipfile
import configparser
zf = zipfile.ZipFile("compressed.zip")
zf_config = zf.open("config_data.conf", "rU")
zf_config_data = zf_config.read().decode('ascii')
config = configparser.ConfigParser()
config.read_string(zf_config_data)
assert config['today']['lunch']=='cheeseburger'
经过思考,以下可能更合适:
import zipfile
import configparser
import io
zf = zipfile.ZipFile("compressed.zip")
zf_config = zf.open("config_data.conf", "rU")
zf_config = io.TextIOWrapper(zf_config)
config = configparser.ConfigParser()
config.read_file(zf_config)
assert config['today']['lunch']=='cheeseburger'
ZipFile
不仅支持read
还支持open
,其中returns是类文件对象。所以,你可以这样做:
zf = zipfile.ZipFile("compressed.zip")
config_file = zf.open("config_data.conf")
sysconfig = configparser.ConfigParser()
sysconfig.readfp(config_file)
如评论中所写,@matthewatabet 的回答不适用于 Python 3.4(和更新版本)。这是因为 ZipFile.open
现在 returns 是一个“类似字节”的对象,不再是“类似文件”的对象。您可以使用:
codecs.getreader("utf-8")(config_file)
使用 UTF-8 编码将 config_file
类字节对象转换为类文件对象。现在的代码是:
import zipfile, configparser, codecs
# Python >= 3.4
with zipfile.ZipFile("compressed.zip") as zf:
config_file = zf.open("config_data.conf") # binary mode
sysconfig = configparser.ConfigParser()
sysconfig.read_file(codecs.getreader("utf-8")(config_file))
这似乎比创建string
更令人满意,但我不知道它是否更有效率...
EDIT 从 Python 3.9 开始,zipfile
模块提供了一个可以处理文本和二进制模式的 zipfile.Path.open
method。默认为文本模式。以下代码工作正常:
# Python >= 3.9
with zipfile.ZipFile("compressed.zip") as zf:
zip_path = zipfile.Path(zf)
config_path = zip_path / "config_data.conf"
config_file = config_path.open() # text mode
sysconfig = configparser.ConfigParser()
sysconfig.read_file(config_file)