我可以使用msilib或其他Python库从.msi文件中提取一个文件吗?
我想做的事情是检查一个特定的文件在MSI中是否存在,并且里面是否包含某个特定的字符串。
我现在的想法是先运行:
db = msilib.OpenDatabase('c:\Temp\myfile.msi',1)
query = "select * from File"
view = db.OpenView(query)
view.Execute(None)
cur_record = view.Fetch() # do this until I get the record I want
print cur_record.GetString(3) # do stuff with this value
然后如果这个文件存在,就用
msiexec /a c:\Temp\myfile.msi /qn TARGETDIR=c:\foo
把所有文件提取出来,然后用某种解析工具来查看我的字符串是否在里面。不过我希望能有一种更简单的方法。
3 个回答
0
MSI的API本身比较复杂,所以关键在于你怎么去简化它。如果你只是偶尔需要用到这个,可能直接在资源管理器里手动浏览cab文件会更简单一些。(文件是通过文件键来存储的,而不是通过文件名)。
1
要知道,在使用Python的时候,你需要处理Windows安装程序的自动化接口。这意味着你需要自己完成所有的数据库连接、查询和处理工作。
如果你能换到C#(或者说PowerShell),你就可以利用一些在Windows安装程序XML(WiX)部署工具基础(DTF)中存在的更高级的类。
using Microsoft.Deployment.WindowsInstaller;
using Microsoft.Deployment.WindowsInstaller.Package;
static void FindAndExtractFiles(string packagePath, string longFileName)
{
using (var installPackage = new InstallPackage(packagePath, DatabaseOpenMode.ReadOnly))
{
if(installPackage.FindFiles(longFileName).Count() > 0 )
installPackage.ExtractFiles();
}
}
你也可以把这个写成ComVisible(True),然后从Python中调用它。
3
注意,正如msilib
的文档所说,“目前不支持读取.cab文件”。更一般来说,这个库是用来创建.msi文件的,而不是用来读取它们的。而且在标准库中没有其他可以满足你需求的工具。
所以,有几个选择:
- 找一个其他的库,比如
pycabinet
。我对这个库不太了解,这只是我搜索到的第一个结果;你可能需要自己再搜索一下。不过它声称提供一个类似于zipfile
的接口来处理CAB文件,这听起来正是你需要的部分。 - 使用
win32com
(如果你安装了pywin32
)或者ctypes
(如果你喜欢挑战)来与底层的COM接口和/或经典的Cabinet API进行交互(我觉得这个API现在已经不推荐使用了,但仍然可以工作)。 - 使用IronPython而不是CPython,这样你可以使用更简单的.NET接口。
由于我这里没有Windows系统,所以无法测试这些方法,但这里有一个用IronPython而不是C#编写的Christopher Painter的.NET解决方案的草图:
import clr
clr.AddReference('Microsoft.Deployment.WindowsInstaller')
clr.AddReference('Microsoft.Deployment.WindowsInstaller.Package')
from Microsoft.Deployment.WindowsInstaller import *
from Microsoft.Deployment.WindowsInstaller.Package import *
def FindAndExtractFiles(packagePath, longFileName):
with InstallPackage(packagePath, DatabaseOpenMode.ReadOnly) as installPackage:
if installPackage.FindFiles(longFileName).Count() > 0:
installPackage.ExtractFiles()