linux link path walk,python之os.walk()与os.path.walk()

本文详细介绍了Python中os.walk()与os.path.walk()函数的使用方法及区别。包括参数说明、函数返回值以及通过具体示例展示了如何利用这两个函数遍历文件系统。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

来源:http://xukaizijian.blog.163.com/blog/#m=0&t=1&c=fks_084067093085083070086087087095085081081071087085087066093

os.walk()

函数声明:walk(top,topdown=True,onerror=None)

1>参数top表示需要遍历的目录树的路径

2>参数topdown的默认值是"True",表示首先返回目录树下的文件,然后在遍历目录树的子目录.Topdown的值为"False"时,则表示先遍历目录树的子目录,返回子目录下的文件,最后返回根目录下的文件

3>参数onerror的默认值是"None",表示忽略文件遍历时产生的错误.如果不为空,则提供一个自定义函数提示错误信息后继续遍历或抛出异常中止遍历

4>该函数返回一个元组,该元组有3个元素,这3个元素分别表示每次遍历的路径名,目录列表和文件列表os,walk()实例:

import os

def VisitDir(path):

for root,dirs,files in os.walk(path):

for filespath in files:

print os.path.join(root,filespath)

if __name__=="__main__":

path="/root"

VisitDir(path)

os.path.walk()

函数声明:walk(top,func,arg)

1>参数top表示需要遍历的目录树的路径

2>参数func表示回调函数,对遍历路径进行处理.所谓回调函数,是作为某个函数的参数使用,当某个时间触发时,程序将调用定义好的回调函数处理某个任务.回调函数必须提供3个参数:第1个参数为walk()的参数tag,第2个参数表示目录列表,第3个参数表示文件列表

3>参数arg是传递给回调参数func的元组.回调函数的一个参数必须是arg,为回调函数提供处理参数.参数arg可以为空

os.path.walk()实例:

import os,os.path

def VisitDir(arg,dirname,names):

for filespath in name:

print os.path.join(dirname,filespath)

if __name__=="__main__":

path="/root"

os.path.walk(path,VisitDir,())

os.path.walk()与os.walk()产生的文件名列表并不相同.os.path.walk()产生目录树下的目录路径和文件路径,而os.walk()只产生文件路径

如下面的例程:

1 # -*- coding: utf-8 -*-

2 import os

3 for root, dirs, files in os.walk('/media/cdrom0'):

4 open('mycd.cdc', 'a').write("%s %s %s" % (root,dirs,files))

完成的功能是讲/media/cdrom0下的目录文件写入到mycd.cdc中。

代码解释:

1. 声明是 utf-8 编码文本;

2. 引入了 os 模块;

3. 使用os.walk() 扫描光盘,并返回三个对象;

4. 使用open()打开mycd.cdc 文件对象,并声明成追加模式,逐行记录以上三个对象。

import os import datetime import shutil import subprocess import re import platform import hashlib def get_commit_id(): cmd = ['git', 'rev-parse', 'HEAD'] try: result = subprocess.check_output(cmd) commit_id = result.decode().strip() if not commit_id: raise Exception('commit id not found') return commit_id except Exception as e: print(e) raise e def remove_pycache(path): for root, dirs, files in os.walk(path): for dir in dirs: if dir == '__pycache__': pycache_dir = os.path.join(root, dir) shutil.rmtree(pycache_dir) def use_shell(): if platform.system() == "Linux": return False return True class SdkPacker: def __init__(self): self.starttime = datetime.datetime.now() self.record('*' * 10 + 'SDK pack init' + '*' * 10) # pip self.pipUrl = os.getenv('SDK_PIP_URL') self.pipTrustHost = os.getenv('SDK_PIP_TRUST_HOST') self.pipArgs = os.getenv('SDK_PIP_ARGS') self.record(f'pipUrl: {self.pipUrl}') self.record(f'pipTrustHost: {self.pipTrustHost}') self.record(f'pipArgs: {self.pipArgs}') # sdk path self.sdkPath = os.path.dirname(os.path.abspath(__file__)) self.outPath = os.path.join(self.sdkPath, 'out') self.enginePath = os.path.join(self.outPath, 'engine') self.remove_path(os.path.join(self.sdkPath, 'build')) self.remove_path(os.path.join(self.sdkPath, 'rpa', 'build')) self.remove_path(self.enginePath) # commit id self.commitId = get_commit_id() self.record(f"commit id:{self.commitId}") # cache path self.cachePath = os.path.join(self.sdkPath, 'out', 'cache') self.cacheZipPath = os.path.join(self.cachePath, f'{self.commitId}.7z') # env self.RPA_PACK_PLATFORM = self.get_env('RPA_PACK_PLATFORM') self.RPA_PACK_ARCH = self.get_env('RPA_PACK_ARCH') self.RPA_VERSION = self.get_env('RPA_PACK_VERSION') if not self.RPA_VERSION or not re.search(r"\d", self.RPA_VERSION): self.RPA_VERSION = "15.0.0" self.RPA_FORCE_REBUILD = self.get_env('RPA_PACK_FORCE_REBUILD') self.platform = platform.system() self.record(f"System: {self.platform}") # tools path self.sdkToolsPath = os.path.join(self.sdkPath, 'out', 'sdk_tools') # output path self.python_out = os.path.join(self.enginePath) if self.RPA_PACK_PLATFORM == 'windows': self.reqsPath = os.path.join(self.sdkPath, 'rpa', 'requirements.txt') self.site_packages = os.path.join(self.enginePath, 'Lib', 'site-packages') elif self.RPA_PACK_PLATFORM in ['linux', 'UOS', 'kylinOS']: self.reqsPath = os.path.join(self.sdkPath, 'rpa', 'requirements_uos.txt') self.site_packages = os.path.join(self.enginePath, 'lib', 'python3.7', 'site-packages') else: raise Exception(f'not support platform: {self.RPA_PACK_PLATFORM} and arch: {self.RPA_PACK_ARCH}') self.seven_zip_out = os.path.join(self.site_packages, 'rpa', 'file_folder') self.ffmpeg_out = os.path.join(self.site_packages, 'rpa', 'win32') self.db2_out = os.path.join(self.site_packages) self.db2_cli_out = os.path.join(self.site_packages, 'ibm_db-3.1.4') self.pip_args = [] if self.pipUrl: self.pip_args.extend(['-i', self.pipUrl]) if self.pipTrustHost: self.pip_args.extend(['--trusted-host', self.pipTrustHost]) if self.pipArgs: self.pip_args.extend(self.pipArgs.split(',')) # self.pip_args.extend(['--no-cache-dir', '--no-warn-script-location']) self.record("sdk pack init end") def run_command(self, command, cwd=None): process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=cwd, shell=use_shell()) while True: output = process.stdout.readline() if output == b'' and process.poll() is not None: break if output: print(output.strip().decode('utf-8', errors='replace')) process.wait() if process.returncode is not 0: raise Exception(f'run command {command} error, return code: {process.returncode}') self.record(f"run command: {command}") def get_env(self, env_key): env_value = os.getenv(env_key) if env_value: self.record(f'{env_key}: {env_value}') else: raise Exception(f'{env_key} not found') return env_value def remove_path(self, path): if os.path.exists(path): try: if os.path.isfile(path): os.remove(path) elif os.path.isdir(path): shutil.rmtree(path) self.record(f"remove {path}: successfully") except Exception as e: self.record(f'remove {path}: {e} error') raise e else: self.record(f"remove {path}: not exists") def record(self, title): end_time = datetime.datetime.now() diff = (end_time - self.starttime) print(f"[{end_time.time()} - {diff.seconds}] {title}") def unzip(self, src, dst): # self.run_command(['7z', 'x', src, '-o' + dst, '-bb0'], cwd=os.path.join(self.sdkToolsPath, '7z')) os.system(f"7z x {src} -o{dst}") self.record(f"unzip {src} to {dict}") def calculate_md5(self, file_path): with open(file_path, "rb") as f: md5_hash = hashlib.md5() for chunk in iter(lambda: f.read(4096), b""): md5_hash.update(chunk) return md5_hash.hexdigest() def copy(self, package_name, *rpa_dir): package = os.path.join(self.sdkToolsPath, package_name) package_out = os.path.join(self.site_packages, 'rpa', *rpa_dir) for file in os.listdir(package): package_file = os.path.join(package, file) shutil.copy(package_file, package_out) self.record(f"{package_file} >> {package_out}") self.record(f"copy {package_name}") def pack(self): # encrypt sdk self.record('*' * 10 + 'SDK pack' + '*' * 10) if self.RPA_FORCE_REBUILD == 'false' and os.path.exists(self.cacheZipPath): self.record('SDK use cache') self.unzip(self.cacheZipPath, self.outPath) else: self.encrypt_sdk() # add version version_path = os.path.join(self.site_packages, 'rpa', 'version', 'version') content = f'{self.RPA_VERSION}\n{datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S")}\n{self.commitId}' with open(version_path, 'w') as f: f.write(content) shutil.copy(version_path, self.enginePath) with open(os.path.join(self.enginePath, 'version'), 'r') as f: self.record(f.read()) # remove cache remove_pycache(self.enginePath) self.record(f"remove engine pycache: {self.enginePath}") self.record("SDK pack end") def link_python(self): pass def is_linux(self): return self.RPA_PACK_PLATFORM in ['linux', 'UOS', 'kylinOS'] def is_windows(self): return self.RPA_PACK_PLATFORM == 'windows' def encrypt_sdk(self): def fix_tk(): # remove mouseinfo tk sys.exit mouseinfo_init_path = os.path.join(self.site_packages, 'mouseinfo', '__init__.py') command = """sed -i "s/sys.exit.*/pass/g" """ + mouseinfo_init_path ret = os.system(command) msg = f"remove mouseinfo tk sys.exit code: {ret}" if ret: raise SystemError(msg) self.record(msg) def install_pywpsrpc(): wheel_path = 'pywpsrpc-2.3.3-cp37-cp37m-manylinux_2_5_x86_64.whl' if self.RPA_PACK_ARCH == "arm64": wheel_path = 'pywpsrpc-2.3.3-cp37-cp37m-manylinux_2_28_aarch64.whl' pywpsrpc_path = os.path.join(self.sdkToolsPath, 'pywpsrpc', wheel_path) self.run_command([python_path, '-m', 'pip', 'install', pywpsrpc_path]) def copy_depends(): shutil.copytree(os.path.join(self.sdkToolsPath, 'deps', 'at-spi2-core'), os.path.join(self.enginePath, 'deps', 'at-spi2-core')) shutil.copytree(os.path.join(self.sdkToolsPath, 'deps', 'wps'), os.path.join(self.enginePath, 'deps', 'wps')) shutil.copytree(os.path.join(self.sdkToolsPath, 'deps', 'xclip'), os.path.join(self.site_packages, 'xclip')) # move python self.record('SDK encrypt') use_cache = False requirements_md5 = self.calculate_md5(self.reqsPath) requirements_cache_path = os.path.join(self.sdkPath, 'out', 'cache', f'{requirements_md5}.7z') if self.RPA_FORCE_REBUILD == 'false': if os.path.exists(requirements_cache_path): use_cache = True python_source = "" python_path = "" if self.is_windows(): python_source = os.path.join(self.sdkToolsPath, 'python') python_path = os.path.join(self.enginePath, "python.exe") elif self.is_linux(): python_source = "/opt/python3.7" python_path = os.path.join(self.enginePath, "bin", "python") if not use_cache: shutil.copytree(python_source, self.enginePath) self.record(f"{python_source} >> {self.enginePath}") if self.is_linux(): os.system(f'apt-get install -y libcairo2-dev libgirepository1.0-dev unixodbc-dev') current_cwd = os.getcwd() self.record(f"current cwd:{current_cwd}") bin_path = os.path.join(self.enginePath, "bin") os.chdir(bin_path) os.system(f'ln -s python3.7 python') os.system(f'ln -s python3.7 python3') self.record("link python3.7 to python python3") os.chdir(current_cwd) # install requirements # comtypes<1.1.11 need 2to3, setuptools<58 support 2to3 self.run_command([python_path, '-m', 'pip', 'install', '--upgrade', 'pip'] + self.pip_args) self.run_command([python_path, '-m', 'pip', 'install', '--upgrade', 'setuptools < 58'] + self.pip_args) self.run_command([python_path, '-m', 'pip', 'install', '-r', self.reqsPath] + self.pip_args) if self.is_windows(): # install db2 shutil.copytree(os.path.join(self.sdkToolsPath, 'db2', 'ibm_db-3.1.4'), os.path.join(self.enginePath, 'Lib', 'site-packages', 'ibm_db-3.1.4')) shutil.copytree(os.path.join(self.sdkToolsPath, 'db2_cli', 'clidriver'), os.path.join(self.enginePath, 'Lib', 'site-packages', 'ibm_db-3.1.4', 'clidriver')) self.run_command([os.path.join(self.enginePath, 'python'), 'setup.py', 'install'], cwd=os.path.join(self.enginePath, 'Lib', 'site-packages', 'ibm_db-3.1.4')) elif self.is_linux(): # install db2 # shutil.copytree(os.path.join(self.sdkToolsPath, 'db2', 'ibm_db-3.1.4'), # os.path.join(self.site_packages, 'ibm_db-3.1.4')) # shutil.copytree(os.path.join(self.sdkToolsPath, 'db2_cli', 'clidriver'), # os.path.join(self.site_packages, 'ibm_db-3.1.4', 'clidriver')) # self.run_command([python_path, 'setup.py', 'install'], # cwd=os.path.join(self.site_packages, 'ibm_db-3.1.4')) fix_tk() install_pywpsrpc() copy_depends() # install cython self.run_command([python_path, '-m', 'pip', 'install', 'cython==0.29.24'] + self.pip_args) self.remove_path(requirements_cache_path) self.run_command(['7z', 'a', '-mx1', requirements_cache_path, self.enginePath], cwd=os.path.join(self.sdkToolsPath, '7z')) else: self.record("requirements use cache") self.unzip(requirements_cache_path, self.outPath) build_path = os.path.join(self.sdkPath, 'build', 'rpa') # encrypt sdk self.run_command([python_path, 'setup.py'], cwd=os.path.join(self.sdkPath, 'rpa')) # uninstall cython self.run_command([python_path, '-m', 'pip', 'uninstall', 'cython', '-y']) # remove pycache remove_pycache(build_path) self.record(f"remove rpa pycache: {build_path}") # copy sdk rpa_path = os.path.join(self.site_packages, 'rpa') shutil.move(build_path, rpa_path) self.record(f"move {build_path} >> {rpa_path}") if self.RPA_PACK_PLATFORM == 'windows': self.copy('activexinput', 'uia', 'activexinput') self.copy("7z", "file_folder") self.copy("ffmpeg", "win32") # save cache self.remove_path(self.cacheZipPath) self.run_command(['7z', 'a', '-mx1', self.cacheZipPath, self.enginePath], cwd=os.path.join(self.sdkToolsPath, '7z')) # self.run_command(['7z', 'a', '-tzip', self.cacheZipPath, '-r', self.enginePath, '-y', '-bb0'], # cwd=os.path.join(self.sdkToolsPath, '7z')) # remove paths self.remove_path(os.path.join(self.sdkPath, 'build')) self.remove_path(build_path) self.record("SDK encrypt end") if __name__ == '__main__': import sys if sys.platform == "win32": # for tests os.environ['RPA_PACK_PLATFORM'] = 'windows' os.environ['RPA_PACK_ARCH'] = 'x64' os.environ['RPA_TARGET_FORMAT'] = 'zip' os.environ['RPA_PACK_GITOKEN'] = 'pack_gitoken' os.environ['RPA_VERSION'] = '1.0.0' os.environ['RPA_GIT_TOKEN'] = 'git_token' os.environ['RPA_FORCE_REBUILD'] = 'false' os.environ['RPA_TOOLS_HOME'] = 'C:\\Repos\\tools' elif sys.platform == "darwin": sys.exit(0) else: os.environ['RPA_PACK_PLATFORM'] = 'linux' os.environ['RPA_PACK_ARCH'] = 'x64' os.environ['RPA_TARGET_FORMAT'] = 'deb' os.environ['RPA_PACK_GITOKEN'] = 'pack_gitoken' os.environ['RPA_VERSION'] = '1.0.0' os.environ['RPA_GIT_TOKEN'] = 'git_token' os.environ['RPA_FORCE_REBUILD'] = 'false' os.environ['RPA_TOOLS_HOME'] = '/home/uos/tools' os.environ['SDK_PIP_URL'] = 'https://repo.datagrand.com/repository/py/simple' packer = SdkPacker() packer.pack() 分解一下项目打包的流程,介绍如何实现打包,如何配置环境,依赖等等,以及是否实现可执行文件,将整个流程用图表表示
最新发布
07-10
<think>我们被要求分析一个Python脚本的SDK打包流程,包括打包机制、环境配置、依赖管理,并确认是否生成可执行文件,最后以图表形式展示整个打包流程。同时,我们有一些引用材料,但要注意这些引用并不是直接针对用户的问题,我们需要结合用户上一次的问题(关于Data Grand Studio中subprocess的KeyboardInterrupt错误)和我们的回答来考虑。 然而,用户当前的问题是关于一个SDK打包流程的,具体是分析`entrypoint.py`脚本中的打包流程。但用户并没有提供`entrypoint.py`的具体内容,而是给出了一个运行该脚本时出现的错误。不过,我们注意到用户运行的是`entrypoint.py`,并且错误发生在`subprocess`模块中。 考虑到用户的问题描述,他想要分解项目打包流程,介绍如何实现打包、配置环境和依赖,并询问是否生成可执行文件,同时希望用图表表示整个流程。 根据引用[3]和[4],我们可以推断用户可能是在使用PyInstaller打包Python程序。引用[3]提到了使用PyInstaller打包成exe文件,引用[4]详细说明了PyInstaller的Analysis参数datas的使用方法。 因此,我们可以假设`entrypoint.py`可能是打包流程的入口脚本,它可能使用PyInstaller或者类似的工具来打包项目。 由于用户没有提供`entrypoint.py`的内容,我们只能根据常见的打包流程进行解释,并参考引用材料。 以下是我们将回答的框架: 1. **打包机制**:介绍如何使用PyInstaller打包Python项目,包括单文件模式和多文件模式,以及如何指定各种参数(如添加数据文件)。 2. **环境配置**:说明打包前需要配置的环境,包括Python环境、依赖库的安装(使用pip)以及可能需要的环境变量。 3. **依赖管理**:如何确保打包过程中包含所有依赖,以及如何处理隐藏的依赖(如动态导入的模块)。 4. **是否生成可执行文件**:明确说明PyInstaller会生成可执行文件(.exe)以及相关的目录结构。 5. **图表展示**:用文字描述图表的结构(由于当前是文本,我们可以用流程图的形式描述,或者用树形结构描述打包后的目录)。 同时,我们将结合用户之前遇到的`KeyboardInterrupt`错误,分析在打包过程中可能出现的类似问题(例如,打包过程耗时较长,用户中断操作,或者子进程超时)。 由于用户要求用图表表示,我们可以在回答中给出一个流程图,用文字描述流程,或者使用mermaid语法(如果支持的话)。但考虑到平台兼容性,我们使用文字描述和简单的流程图。 流程图如下: 1. 准备项目:确保项目结构清晰,包含所有必要的文件和资源。 2. 创建虚拟环境(可选):为了避免依赖冲突,建议在虚拟环境中进行打包。 3. 安装依赖:使用pip安装项目所需的依赖库。 4. 安装PyInstaller:在打包环境中安装PyInstaller。 5. 编写打包脚本或命令:使用PyInstaller命令行或编写spec文件进行配置。 6. 执行打包命令:运行打包命令(可能会调用`entrypoint.py`作为入口)。 7. 处理打包过程中的错误:如遇到错误(如`KeyboardInterrupt`)需排查原因。 8. 获取可执行文件:在dist目录中生成可执行文件。 下面开始正式回答。</think>### Python SDK打包流程详解 #### 1. 打包机制分析 根据引用[3]和[4],Python SDK打包主要使用PyInstaller工具实现,核心机制如下: ```mermaid graph TD A[源代码] --> B[PyInstaller分析] B --> C[收集依赖] C --> D[构建可执行文件] D --> E[资源文件打包] E --> F[生成输出目录] ``` **关键步骤**: 1. **依赖分析**:PyInstaller扫描`import`语句识别所有依赖库 2. **字节码编译**:将.py文件编译为.pyc字节码 3. **资源打包**:通过`datas`参数处理非代码资源(如图片、配置文件) 4. **可执行文件生成**:创建独立可执行文件(单文件或多文件模式) 引用[4]详细说明了资源文件处理机制:`datas=[('src/README.txt', '.')]`表示将文件复制到输出根目录[^4]。 #### 2. 环境配置流程 ```mermaid graph LR A[Python环境] --> B[虚拟环境] B --> C[安装依赖] C --> D[配置打包参数] ``` **关键配置**: 1. **Python基础环境**:确保Python解释器路径正确(如引用中`C:/Users/.../python.exe`) 2. **虚拟环境**:推荐使用`venv`隔离项目依赖 3. **依赖安装**:通过`pip install -r requirements.txt`安装所有依赖(引用[2]) 4. **路径配置**:正确设置资源文件路径(如图标、配置文件) #### 3. 依赖管理机制 | 依赖类型 | 管理方式 | 示例 | |----------------|-----------------------------------|--------------------------| | Python库 | 自动扫描 + requirements.txt | `numpy`, `pandas` | | 数据文件 | datas参数显式声明 | `datas=[('images/*.png', 'imgs')]` [^4] | | 二进制依赖 | --add-binary参数 | DLL文件, SO文件 | | 隐藏依赖 | --hidden-import参数 | 动态导入的模块 | **特殊依赖处理**: ```python # 示例:处理动态导入 a = Analysis(['app.py'], hiddenimports=['pkg.mod1', 'pkg.mod2'], datas=[('config.ini', '.')]) ``` #### 4. 可执行文件生成 根据引用[3],PyInstaller提供两种打包模式: 1. **单文件模式**:`pyinstaller -F entrypoint.py` - 所有资源打包到单个.exe文件 - 启动时解压到临时目录 2. **多文件模式**:`pyinstaller -D entrypoint.py` - 主exe + 依赖库 + 资源文件 - 更快的启动速度 - 更易调试 **输出结构**: ``` dist/ ├── entrypoint.exe # 主可执行文件 ├── lib/ # 依赖库 ├── images/ # 图片资源 └── config.ini # 配置文件 ``` #### 5. 完整打包流程图 ```mermaid flowchart TB subgraph 准备阶段 A[创建虚拟环境] --> B[安装依赖] B --> C[验证环境 python/pip] end subgraph 配置阶段 D[编写.spec文件] --> E[配置资源路径] E --> F[设置隐藏依赖] end subgraph 打包阶段 G[执行打包命令] --> H[资源收集] H --> I[字节码编译] I --> J[生成可执行文件] end subgraph 输出阶段 K[验证可执行文件] --> L[分发打包结果] end 准备阶段 --> 配置阶段 --> 打包阶段 --> 输出阶段 ``` #### 6. 关键注意事项 1. **路径问题**:所有路径必须使用**绝对路径**(引用中`d:/sdk-15.0/sdk/`) 2. **环境隔离**:务必在虚拟环境中打包避免污染系统环境 3. **杀毒软件**:打包过程可能触发误报,需添加信任 4. **版本兼容**:确保PyInstaller版本Python版本匹配 5. **调试模式**:首次打包使用`--debug`参数输出详细日志 > **打包验证命令**: > `dist/entrypoint.exe --test-run` 测试生成的可执行文件功能完整性[^3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值