前面介紹了一種最笨的方式,他的缺點就是冗餘太多,浪費空間太大。
今天介紹一種最佳化方法,僅抽取程式中用到的部分。
要下班了,先貼上實現代碼,改天有空再補上原理。
#-*- coding:gbk -*-import sysimport osimport shutil#獲得程式中所有模組的路徑def getModulesPath() :lst = []#sys.modules是一個字典,資料格式如下:#{'site': <module 'site' from 'D:\Python27\lib\site.pyc'>,for v in sys.modules.itervalues() :s = str(v)if "from" in s:data = s.split("'")lst.append(data[-2])else :print "module : ", sreturn lst#抽取檔案def extractFiles(destDir, files) :destDir.replace("/", "\\")if destDir[-1] != '\\' :destDir += '\\'for f in files :dest = filiterPath(destDir, f)copyF(dest, f)#過濾路徑 去掉最大絕對路徑def filiterPath(destDir, srcFile) :dest = destDirmaxLen = 0for path in sys.path :lenp = len(path)if lenp < len(srcFile) and path == srcFile[:lenp] :if maxLen < lenp :dest = destDir + srcFile[lenp+1:]maxLen = lenpdest.replace("/", "\\")if '.' in dest : #去掉檔案名稱p = dest.rfind('\\')if p >= 0 :dest = dest[:p]return dest#拷貝檔案#如果目標路徑不存在,則建立def copyF(destDir, srcFile) :if not os.path.isfile(srcFile) :print "error : file %s not exist!" % srcFilereturn Falseif not os.path.isdir(destDir) :os.mkdir(destDir)print "make dir:", destDirtry :shutil.copy2(srcFile, destDir)print "copy file : %s to %s" % (srcFile, destDir)except IOError:print "error : copy %s to %s faild" % (srcFile, destDir)return Falsereturn Truedef test() :a = getModulesPath()extractFiles("testpg\\", a) #抽取後的檔案會放到testpg目錄下
注意,可在c++程式結束時,調用test()方法執行抽取,則程式用到的所有py都會被抽取出來(包括自己寫的和系統的 ^o^ )。然後將抽取出來的py檔案,壓縮成python27.zip,和python27.dll一起放置到C++程式目錄。
原理也很簡單:
sys.modules存貯了程式運行以來的所有模組,以及模組所在py檔案的絕對路徑,這也是程式運行時所依賴的所有模組。將這些檔案的絕對路徑去掉,打包成pythonXX.zip,放置到c++應用程式目錄下,則程式可自動搜尋到zip檔案中的py檔案。
去掉絕對路徑,要依據sys.path中python路徑,去掉最大長度的路徑。如:
sys.path = ['d:\\python27', 'd:\\python27\\lib', 'd:\\python27\\lib\\lib-tk', ...],某py檔案的路徑 是 d:\python27\lib\aaa\bbb\xxx.py,那麼他的相對路徑應該是aaa\bbb,而不是lib\aaa\bbb.
打包後的目錄組織: