当前位置: 代码网 > it编程>前端脚本>Python > 基于python自制一个软件工具安装包

基于python自制一个软件工具安装包

2025年08月01日 Python 我要评论
思考如何将制作的软件工具分发给用户?打成压缩包分发给用户;制作安装程序本文介绍了一种将软件工具打包为独立安装程序的方法。核心思路是将目录文件转换为base64编码的json文件,再通过解码程序还原为可

思考

如何将制作的软件工具分发给用户?

打成压缩包分发给用户;

制作安装程序

本文介绍了一种将软件工具打包为独立安装程序的方法。核心思路是将目录文件转换为base64编码的json文件,再通过解码程序还原为可执行文件。

内容说明

主要包含两个python脚本:directory_to_base64.py将指定目录转换为包含文件内容的json文件;base64_to_directory.py则执行反向操作,将json还原为目录结构。文章详细说明了使用pyinstaller打包时的注意事项,包括资源文件路径处理、版本信息配置等,并提供了完整的示例代码和spec文件配置模板。这种方法适用于需要将多个文件打包为单一可执行安装程序的场景。

核心代码

directory_to_base64.py

import os
import base64
import json
import argparse
from pathlib import path

def file_to_base64(file_path):
    """将文件内容转换为 base64 编码"""
    try:
        with open(file_path, 'rb') as file:
            content = file.read()
            return base64.b64encode(content).decode('utf-8')
    except exception as e:
        print(f"error reading file {file_path}: {e}")
        return none

def directory_to_dict(dir_path):
    """递归将目录结构转换为字典"""
    result = {}
    for item in os.listdir(dir_path):
        item_path = os.path.join(dir_path, item)
        if os.path.isfile(item_path):
            base64_content = file_to_base64(item_path)
            if base64_content is not none:
                result[item] = {
                    'type': 'file',
                    'content': base64_content
                }
        elif os.path.isdir(item_path):
            result[item] = {
                'type': 'directory',
                'content': directory_to_dict(item_path)
            }
    return result

def main():
    parser = argparse.argumentparser(description='convert a directory and its contents to base64 encoded json')
    parser.add_argument('--input', '-i', required=true, help='input directory path')
    parser.add_argument('--output', '-o', required=true, help='output json file path')
    args = parser.parse_args()

    input_dir = args.input
    output_file = args.output

    if not os.path.isdir(input_dir):
        print(f"error: input directory '{input_dir}' does not exist or is not a directory.")
        return

    try:
        # 创建输出文件的目录(如果不存在)
        output_dir = os.path.dirname(output_file)
        if output_dir:
            os.makedirs(output_dir, exist_ok=true)

        # 转换目录结构为字典
        dir_dict = directory_to_dict(input_dir)

        # 添加元数据
        metadata = {
            'root_directory': os.path.basename(os.path.abspath(input_dir)),
            'total_files': sum(1 for _ in path(input_dir).rglob('*') if os.path.isfile(_)),
            'total_directories': sum(1 for _ in path(input_dir).rglob('*') if os.path.isdir(_))
        }

        result = {
            'metadata': metadata,
            'content': dir_dict
        }

        # 写入 json 文件
        with open(output_file, 'w') as f:
            json.dump(result, f, indent=2)

        print(f"successfully converted directory '{input_dir}' to base64 encoded json in '{output_file}'.")

    except exception as e:
        print(f"an error occurred: {e}")

if __name__ == "__main__":
    main()    

base64_to_directory.py

import os
import base64
import json
import argparse
import sys
import pyexpat

from pyexpat.errors import messages


def decode_base64_to_file(base64_content, output_path):
    """将 base64 编码内容写入文件"""
    try:
        with open(output_path, 'wb') as file:
            file.write(base64.b64decode(base64_content))
        return true
    except exception as e:
        print(f"error writing file {output_path}: {e}")
        return false


def process_directory(content_dict, output_dir):
    """递归处理目录结构并还原文件"""
    for item_name, item_data in content_dict.items():
        item_path = os.path.join(output_dir, item_name)

        if item_data['type'] == 'file':
            # 创建文件
            base64_content = item_data['content']
            if decode_base64_to_file(base64_content, item_path):
                print(f"created file: {item_path}")
        elif item_data['type'] == 'directory':
            # 创建目录
            os.makedirs(item_path, exist_ok=true)
            print(f"created directory: {item_path}")
            # 递归处理子目录
            process_directory(item_data['content'], item_path)

def resource_path(relative_path):
    """获取资源的绝对路径,适应打包后的环境"""
    if hasattr(sys, '_meipass'):
        # 打包后的环境
        return os.path.join(sys._meipass, relative_path)
    # 开发环境
    return os.path.join(os.path.abspath("."), relative_path)

def main():
    """    parser = argparse.argumentparser(description='decode a base64 encoded json file back to directory structure')
    parser.add_argument('--input', '-i', required=true, help='input json file path')
    parser.add_argument('--output', '-o', required=true, help='output directory path')
    args = parser.parse_args()"""

    # 使用示例
    input_file = resource_path("input.json")
    output_dir = "./tool"

    """if not os.path.isfile(input_file):
        print(f"error: input file '{input_file}' does not exist or is not a file.")
        return
"""
    try:
        # 读取 json 文件
        with open(input_file, 'r') as f:
            data = json.load(f)

        # 创建输出目录(如果不存在)
        os.makedirs(output_dir, exist_ok=true)

        # 获取元数据
        metadata = data.get('metadata', {})
        root_directory = metadata.get('root_directory', '')
        total_files = metadata.get('total_files', 0)
        total_dirs = metadata.get('total_directories', 0)

        print(f"decoding directory: {root_directory}")
        print(f"total files expected: {total_files}")
        print(f"total directories expected: {total_dirs}")
        print(f"output location: {output_dir}")
        print("starting decoding process...")

        # 处理内容
        content_dict = data.get('content', {})
        process_directory(content_dict, output_dir)

        print("decoding completed successfully!")

    except exception as e:
        print(f"an error occurred: {e}")


if __name__ == "__main__":
    main()

base64_to_directory.spec

# -*- mode: python ; coding: utf-8 -*-

a = analysis(
    ['d:\\workspace\\python_work\\learn\\sttest\\build\\base64_to_directory.py'],
    pathex=[],
    binaries=[],
    datas=[('input.json', '.')],
    hiddenimports=[],
    hookspath=[],
    hooksconfig={},
    runtime_hooks=[],
    excludes=[],
    noarchive=false,
    optimize=0,
)
pyz = pyz(a.pure)

exe = exe(
    pyz,
    a.scripts,
    a.binaries,
    a.datas,
    [],
    name='csvfilebatchgenerationtoolinstall',
    debug=false,
    bootloader_ignore_signals=false,
    strip=false,
    upx=true,
    upx_exclude=[],
    runtime_tmpdir=none,
    console=true,
    disable_windowed_traceback=false,
    argv_emulation=false,
    target_arch=none,
    codesign_identity=none,
    entitlements_file=none,
    version='version.txt'     # 指定版本信息文件
)

version.txt

# 版本信息文件
vsversioninfo(
  ffi=fixedfileinfo(
    filevers=(1, 0, 0, 0),
    prodvers=(1, 0, 0, 0),
    mask=0x3f,
    flags=0x0,
    os=0x40004,
    filetype=0x1,
    subtype=0x0,
    date=(0, 0)
  ),
  kids=[
    stringfileinfo(
      [
        stringtable(
          '080404b0',
          [
            stringstruct('companyname', ''),
            stringstruct('filedescription','工具安装程序'),
            stringstruct('fileversion', '1.0.0'),
            stringstruct('internalname', 'csv_data_install'),
            stringstruct('legalcopyright', '© 2025 company. all rights reserved.'),
            stringstruct('originalfilename', 'install.exe'),
            stringstruct('productname', 'toolinstall'),
            stringstruct('productversion', '1.0.0')
          ]
        )
      ]
    ),
    varfileinfo(
      [
        varstruct('translation', [2052, 1200])  # 2052=中文
      ]
    )
  ]
)

注意事项

input.json文件作为数据资源文件,需要通过os.path.join(sys._meipass, relative_path)设定打包后的路径。datas=[('input.json', '.')]指定资源文件(‘原路径’,‘目标路径’)。执行命令pyinstaller "spec文件路径"打包。

到此这篇关于基于python自制一个软件工具安装包的文章就介绍到这了,更多相关python软件安装包内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com