Nhóm các tệp dữ liệu với PyInstaller (--onefile)


107

Tôi đang cố gắng tạo EXE một tệp với PyInstaller bao gồm một hình ảnh và một biểu tượng. Tôi không thể cho cuộc sống của tôi để nó hoạt động với --onefile.

Nếu tôi làm --onedirthì tất cả đều hoạt động rất tốt. Khi tôi sử dụng --onefile, nó không thể tìm thấy các tệp bổ sung được tham chiếu (khi chạy EXE đã biên dịch). Nó tìm thấy các tệp DLL và mọi thứ khác đều ổn, không chỉ là hai hình ảnh.

Tôi đã xem trong \Temp\_MEI95642\tệp tạm thời được tạo khi chạy EXE ( ví dụ) và các tệp thực sự nằm trong đó. Khi tôi thả EXE vào thư mục tạm thời đó, nó sẽ tìm thấy chúng. Rất bối rối.

Đây là những gì tôi đã thêm vào .spectệp

a.datas += [('images/icon.ico', 'D:\\[workspace]\\App\\src\\images\\icon.ico',  'DATA'),
('images/loaderani.gif','D:\\[workspace]\\App\\src\\images\\loaderani.gif','DATA')]     

Tôi nên nói thêm rằng tôi đã cố gắng không đưa chúng vào các thư mục con, cũng không tạo ra sự khác biệt.

Chỉnh sửa: Câu trả lời mới hơn được đánh dấu là đúng do cập nhật PyInstaller.


11
cảm ơn bạn rất nhiều! dòng ở đây ( a.datas += ...) thực sự đã giúp tôi vừa rồi. các cuộc đàm phán tài liệu PyInstaller về việc sử dụng COLLECTnhưng điều đó không đưa file vào nhị phân khi sử dụng--onefile
Igor Serebryany

@IgorSerebryany: Biệt phái! Tôi chỉ có cùng một vấn đề.
Hubro

.Exe của tôi bị treo khi tôi bấm vào thanh menu nếu tôi sử dụng
iacopo

1
Đưa vào tài khoản mà temp folder biến mất khi thực hiện kết thúc, vì vậy để kiểm tra những gì bên trong nó đặt một listdir của sys._MEIPASS trong chương trình của bạn chính
hithwen

Có cách nào sử dụng cú pháp Tree () mà tôi dường như đã thấy ở khắp nơi không?
fatuhoku

Câu trả lời:


152

Các phiên bản mới hơn của PyInstaller không đặt envbiến nữa, vì vậy câu trả lời tuyệt vời của Shish sẽ không hoạt động. Bây giờ đường dẫn được đặt là sys._MEIPASS:

def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
    try:
        # PyInstaller creates a temp folder and stores path in _MEIPASS
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")

    return os.path.join(base_path, relative_path)

10
Tôi đang sử dụng pyinstaller 2 với python 2.7 và tôi không có _MEIPASS2env, nhưng sys._MEIPASShoạt động tốt, vì vậy hãy +1. Tôi đề nghị:path = getattr(sys, '_MEIPASS', os.getcwd())
kbec

2
+1. Cảm ơn vì điều đó. Cố gắng sử dụng biến môi trường _MEIPASS2 trong một thời gian, rõ ràng là tôi đã viết mã của mình khi nó vẫn là biến môi trường, vì tôi nhớ nó đang hoạt động. Đột nhiên, nó dừng lại, khi tôi biên dịch lại gần đây.
Favil Orbedios

8
Tôi khuyên bạn nên bắt cái AttributeErrorthay vì cái chung chung hơn Exception. Tôi gặp phải sự cố trong đó tôi thiếu nhập hệ thống và đường dẫn được mặc định một cách âm thầm os.path.abspath.
Aaron

Bạn có thể giúp giải quyết vấn đề của tôi .
Phillip

1
Sử dụng thư mục làm việc hiện tại trong trường hợp _MEIPASS không được đặt là sai. Hãy xem câu trả lời của tôi .
Jonathon Reinhart

51

pyinstaller giải nén dữ liệu của bạn vào một thư mục tạm thời và lưu trữ đường dẫn thư mục này trong _MEIPASS2biến môi trường. Để lấy _MEIPASS2dir ở chế độ đóng gói và sử dụng thư mục cục bộ ở chế độ giải nén (phát triển), tôi sử dụng cái này:

def resource_path(relative):
    return os.path.join(
        os.environ.get(
            "_MEIPASS2",
            os.path.abspath(".")
        ),
        relative
    )

Đầu ra:

# in development
>>> resource_path("app_icon.ico")
"/home/shish/src/my_app/app_icon.ico"

# in production
>>> resource_path("app_icon.ico")
"/tmp/_MEI34121/app_icon.ico"

10
Làm thế nào, khi nào và ở đâu một người sẽ sử dụng nó?
gseattle

4
Bạn nên sử dụng tập lệnh này trong tệp .py mà bạn đang cố gắng biên dịch bằng PyInstaller. Đừng đặt đoạn mã này vào tệp .spec, điều đó sẽ không hoạt động. Truy cập tệp của bạn bằng cách thay thế đường dẫn bạn thường nhập resource_path("file_to_be_accessed.mp3"). Hãy cảnh giác rằng bạn nên sử dụng câu trả lời max 'cho phiên bản PyInstaller hiện tại.
Tăng tốc-G

1
Câu trả lời này có cụ thể cho --one-filetùy chọn sử dụng không?
fatuhoku

Bạn có thể giúp giải quyết vấn đề của tôi .
Phillip

Sử dụng thư mục làm việc hiện tại trong trường hợp _MEIPASS không được đặt là sai. Hãy xem câu trả lời của tôi .
Jonathon Reinhart

30

Tất cả các câu trả lời khác sử dụng thư mục làm việc hiện tại trong trường hợp ứng dụng không sys._MEIPASSđược cài đặt PyInstalled (tức là chưa được thiết lập). Điều đó là sai, vì nó ngăn bạn chạy ứng dụng của mình từ một thư mục khác với thư mục chứa tập lệnh của bạn.

Một giải pháp tốt hơn:

import sys
import os

def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
    base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
    return os.path.join(base_path, relative_path)

Cảm ơn Jon, chức năng của bạn đã giúp tôi hôm nay giải quyết một vấn đề. Tôi chỉ có một câu hỏi. Tại sao một số viết _MEIPASS2 thay vì _MEIPASS? Khi tôi thử thêm 2 cái trước đó, nó không hoạt động.
Ahmed AbdelKhalek

Tôi nghĩ os.env['_MEIPASS2'](sử dụng môi trường OS) là một phương pháp cũ để lấy thư mục. AFAIK sys._MEIPASSlà phương pháp chính xác duy nhất hiện nay.
Jonathon Reinhart

Xin chào, giải pháp của bạn hoạt động tốt khi resource_path()ở trong tập lệnh chính. Có cách nào để làm cho nó hoạt động khi nó được viết trong một mô-đun không? Hiện tại, nó sẽ cố gắng lấy tài nguyên trong thư mục chứa mô-đun chứ không phải chính.
Guimoute 24/09/18

1
@Guimoute có vẻ như mã trong câu trả lời này đang hoạt động như được thiết kế: nó bản địa hóa các tài nguyên cho mô-đun cung cấp nó vì nó sử dụng __file__. Nếu bạn muốn một mô-đun có thể truy cập các tài nguyên bên ngoài phạm vi riêng của nó thì bạn sẽ phải triển khai rằng mã nhập cung cấp đường dẫn đến chúng để mô-đun của bạn sử dụng, ví dụ: bằng cách mô-đun cung cấp lệnh gọi "set_resource_location ()" mà cuộc gọi của nhà nhập khẩu - đừng nghĩ điều này khác với cách bạn làm khi không sử dụng pyinstaller.
barny

@barny Cảm ơn vì gợi ý! Tôi sẽ thử một cái gì đó dọc theo những dòng đó.
Guimoute

14

Có lẽ tôi đã bỏ lỡ một bước hoặc làm điều gì đó sai nhưng các phương pháp ở trên không gói các tệp dữ liệu với PyInstaller thành một tệp exe. Hãy để tôi chia sẻ các bước những gì tôi đã làm.

  1. Bước: Viết một trong các phương thức trên vào tệp py của bạn bằng cách nhập mô-đun hệ điều hành và hệ điều hành. Tôi đã thử cả hai. Cuối cùng là:

    def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
        base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
        return os.path.join(base_path, relative_path)
  2. step: Write, pyi-makepec file.py , vào bảng điều khiển, để tạo tệp file.spec.

  3. Bước: Mở, file.spec bằng Notepad ++ để thêm các tệp dữ liệu như bên dưới:

    a = Analysis(['C:\\Users\\TCK\\Desktop\\Projeler\\Converter-GUI.py'],
                 pathex=['C:\\Users\\TCK\\Desktop\\Projeler'],
                 binaries=[],
                 datas=[],
                 hiddenimports=[],
                 hookspath=[],
                 runtime_hooks=[],
                 excludes=[],
                 win_no_prefer_redirects=False,
                 win_private_assemblies=False,
                 cipher=block_cipher)
    #Add the file like the below example
    a.datas += [('Converter-GUI.ico', 'C:\\Users\\TCK\\Desktop\\Projeler\\Converter-GUI.ico', 'DATA')]
    pyz = PYZ(a.pure, a.zipped_data,
         cipher=block_cipher)
    exe = EXE(pyz,
              a.scripts,
              exclude_binaries=True,
              name='Converter-GUI',
              debug=False,
              strip=False,
              upx=True,
              #Turn the console option False if you don't want to see the console while executing the program.
              console=False,
              #Add an icon to the program.
              icon='C:\\Users\\TCK\\Desktop\\Projeler\\Converter-GUI.ico')
    
    coll = COLLECT(exe,
                   a.binaries,
                   a.zipfiles,
                   a.datas,
                   strip=False,
                   upx=True,
                   name='Converter-GUI')
  4. Bước: Tôi đã làm theo các bước trên, sau đó lưu tệp đặc tả. Cuối cùng, mở bảng điều khiển và ghi, pyinstaller file.spec (trong trường hợp của tôi, tệp = Converter-GUI).

Kết luận: Vẫn còn nhiều hơn một tệp trong thư mục dist.

Lưu ý: Tôi đang sử dụng Python 3.5.

CHỈNH SỬA: Cuối cùng thì nó cũng hoạt động với phương pháp của Jonathan Reinhart.

  1. Bước: Thêm các mã dưới đây vào tệp python của bạn bằng cách nhập hệ thống và hệ điều hành.

    def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
        base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
        return os.path.join(base_path, relative_path)
  2. Bước: Gọi hàm trên với việc thêm đường dẫn tệp của bạn:

    image_path = resource_path("Converter-GUI.ico")
  3. Bước: Viết biến ở trên gọi hàm đến nơi mã của bạn cần đường dẫn. Trong trường hợp của tôi, đó là:

        self.window.iconbitmap(image_path)
  4. Bước: Mở bảng điều khiển trong cùng thư mục của tệp python của bạn, viết mã như dưới đây:

        pyinstaller --onefile your_file.py
  5. Bước: Mở tệp .spec của tệp python và nối mảng a.datas và thêm biểu tượng vào lớp exe, được đưa ra ở trên trước khi chỉnh sửa ở bước thứ 3.
  6. Bước: Lưu và thoát khỏi tệp đường dẫn. Chuyển đến thư mục của bạn bao gồm tệp spec và py. Mở lại cửa sổ bảng điều khiển và nhập lệnh dưới đây:

        pyinstaller your_file.spec

Sau bước 6. một tệp của bạn đã sẵn sàng để sử dụng.


Cảm ơn @dilde! Không phải a.datasmảng từ bước 5 có nhiều chuỗi, hãy xem pythonhosted.org/PyInstaller/spec-files.html#adding-data-files để tham khảo.
Ian Campbell

Xin lỗi, tôi không thể hiểu một phần tin nhắn của bạn như tôi muốn vì tiếng Anh của tôi yếu. Phần đó là "Không phải là a.datas ...." , Bạn có muốn viết 'Lưu ý rằng a.datas ... " Có điều gì sai với những gì tôi đã viết về việc thêm chuỗi vào mảng a.datas không?
dildeolupbiten

Giáo sư! Cần lưu ý rằng ... ya, xin lỗi về lỗi đánh máy. Các bước của bạn rất hiệu quả đối với tôi :), Tôi không thể tìm thấy thông tin này trong tài liệu của họ hoặc bất kỳ nơi nào khác.
Ian Campbell

8

Thay vì viết lại tất cả mã đường dẫn của tôi như được đề xuất, tôi đã thay đổi thư mục làm việc:

if getattr(sys, 'frozen', False):
    os.chdir(sys._MEIPASS)

Chỉ cần thêm hai dòng đó vào đầu mã của bạn, bạn có thể để nguyên phần còn lại.


2
Không. Các ứng dụng tốt hiếm khi thay đổi thư mục làm việc. Có nhiều cách tốt hơn.
Jonathon Reinhart

3

Sửa đổi nhẹ cho câu trả lời được chấp nhận.

def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
    if hasattr(sys, '_MEIPASS'):
        return os.path.join(sys._MEIPASS, relative_path)

    return os.path.join(os.path.abspath("."), relative_path)

Sử dụng thư mục làm việc hiện tại trong trường hợp _MEIPASS không được đặt là sai. Hãy xem câu trả lời của tôi .
Jonathon Reinhart

1

Khiếu nại / câu hỏi phổ biến nhất mà tôi đã thấy trên wrt PyInstaller là "mã của tôi không thể tìm thấy tệp dữ liệu mà tôi chắc chắn đã đưa vào gói, nó ở đâu?" Và không dễ dàng để xem mã của bạn là gì / ở đâu đang tìm kiếm vì mã được trích xuất ở vị trí tạm thời và bị xóa khi thoát. Thêm đoạn mã này để xem những gì được bao gồm trong onefile của bạn và nó ở đâu, bằng cách sử dụng @Jonathon Reinhart'sresource_path()

for root, dirs, files in os.walk(resource_path("")):
    print(root)
    for file in files:
        print( "  ",file)

0

Tôi thấy các câu trả lời hiện có khó hiểu và mất nhiều thời gian để tìm ra vấn đề ở đâu. Đây là tổng hợp mọi thứ tôi tìm thấy.

Khi tôi chạy ứng dụng của mình, tôi gặp lỗi Failed to execute script foo(nếu foo.pylà tệp chính). Để khắc phục sự cố này, đừng chạy PyInstaller với --noconsole(hoặc chỉnh sửa main.specđể thay đổi console=False=> console=True). Với điều này, hãy chạy tệp thực thi từ một dòng lệnh và bạn sẽ thấy lỗi.

Điều đầu tiên cần kiểm tra là nó đóng gói các tệp bổ sung của bạn một cách chính xác. Bạn nên thêm các bộ giá trị như ('x', 'x')nếu bạn muốn thư mục xđược đưa vào.

Sau khi nó gặp sự cố, đừng nhấp vào OK. Nếu đang sử dụng Windows, bạn có thể sử dụng Tìm kiếm mọi thứ . Tìm kiếm một trong các tệp của bạn (ví dụ. sword.png). Bạn sẽ tìm thấy đường dẫn tạm thời nơi nó giải nén các tệp (ví dụ C:\Users\ashes999\AppData\Local\Temp\_MEI157682\images\sword.png:). Bạn có thể duyệt qua thư mục này và đảm bảo rằng nó bao gồm mọi thứ. Nếu bạn không thể tìm thấy nó theo cách này, hãy tìm một cái gì đó như main.exe.manifest(Windows) hoặc python35.dll(nếu bạn đang sử dụng Python 3.5).

Nếu trình cài đặt bao gồm mọi thứ, thì vấn đề có thể xảy ra tiếp theo là I / O tệp: mã Python của bạn đang tìm kiếm trong thư mục của tệp thực thi, thay vì thư mục tạm thời, cho tệp.

Để khắc phục điều đó, bất kỳ câu trả lời nào cho câu hỏi này đều hoạt động. Cá nhân tôi thấy rằng tất cả chúng đều hoạt động được: thay đổi thư mục có điều kiện, điều đầu tiên trong tệp điểm nhập chính của bạn và mọi thứ khác đều hoạt động như cũ:

if hasattr(sys, '_MEIPASS'): os.chdir(sys._MEIPASS)


1
Lấy làm tiếc. Nhưng thay đổi thư mục không bao giờ là câu trả lời đúng. Nếu người dùng cung cấp một đường dẫn đến ứng dụng, họ mong đợi nó có liên quan đến thư mục hiện tại. Nếu bạn thay đổi điều đó, nó sẽ là sai lầm.
Jonathon Reinhart

0

Nếu bạn vẫn đang cố gắng đặt các tệp liên quan đến tệp thực thi của mình thay vì trong thư mục tạm thời, bạn cần phải tự sao chép tệp đó. Đây là cách tôi đã hoàn thành nó.

https://stackoverflow.com/a/59415662/999943

Bạn thêm một bước trong tệp đặc tả để sao chép hệ thống tệp vào biến DISTPATH.

Hy vọng rằng sẽ giúp.


0

Tôi đã đối phó với vấn đề này trong một thời gian dài (tốt, rất lâu). Tôi đã tìm kiếm hầu hết mọi nguồn nhưng mọi thứ không theo khuôn mẫu trong đầu tôi.

Cuối cùng, tôi nghĩ rằng tôi đã tìm ra các bước chính xác để làm theo, tôi muốn chia sẻ.

Lưu ý rằng, câu trả lời của tôi sử dụng thông tin về câu trả lời của những người khác về câu hỏi này.

Cách tạo tệp thực thi độc lập của một dự án python.

Giả sử, chúng ta có một project_folder và cây tệp như sau:

project_folder/
    main.py
    xxx.py # modules
    xxx.py # modules
    sound/ # directory containing the sound files
    img/ # directory containing the image files
    venv/ # if using a venv

Trước hết, giả sử bạn đã xác định đường dẫn đến sound/img/thư mục của mình thành các biến sound_dirimg_dirnhư sau:

img_dir = os.path.join(os.path.dirname(__file__), "img")
sound_dir = os.path.join(os.path.dirname(__file__), "sound")

Bạn phải thay đổi chúng, như sau:

img_dir = resource_path("img")
sound_dir = resource_path("sound")

Ở đâu, resource_path()được định nghĩa ở đầu tập lệnh của bạn là:

def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
    base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
    return os.path.join(base_path, relative_path)

Kích hoạt env ảo nếu sử dụng một địa điểm,

Cài đặt PyInstaller nếu bạn đã làm chưa, bằng cách: pip3 install pyinstaller.

Run: pyi-makespec --onefile main.pyđể tạo tệp đặc tả cho quá trình biên dịch và xây dựng.

Điều này sẽ thay đổi phân cấp tệp thành:

project_folder/
    main.py
    xxx.py # modules
    xxx.py # modules
    sound/ # directory containing the sound files
    img/ # directory containing the image files
    venv/ # if using a venv
    main.spec

Mở (với một edior) main.spec:

Ở trên cùng, hãy chèn:

added_files = [

("sound", "sound"),
("img", "img")

]

Sau đó, thay đổi dòng datas=[],thànhdatas=added_files,

Chi tiết các thao tác thực hiện main.specxem tại đây.

Chạy pyinstaller --onefile main.spec

Và đó là tất cả, bạn có thể chạy maintrong project_folder/disttừ bất cứ nơi nào, mà không cần phải bất cứ điều gì khác trong thư mục của nó. Bạn chỉ có thể phân phối maintệp đó . Nó bây giờ, một độc lập thực sự .


@JonathonReinhart nếu bạn vẫn còn ở đây, tôi muốn thông báo với bạn rằng tôi đã sử dụng chức năng của bạn trong câu trả lời của mình.
muyustan

0

Sử dụng câu trả lời tuyệt vời từ MaxBài đăng này về việc thêm các tệp dữ liệu bổ sung như hình ảnh hoặc âm thanh và nghiên cứu / thử nghiệm của riêng tôi, tôi đã tìm ra cách tôi tin là cách dễ nhất để thêm các tệp như vậy.

Nếu bạn muốn xem một ví dụ trực tiếp, kho lưu trữ của tôi ở đây trên GitHub.

Lưu ý: đây là để biên dịch bằng lệnh --onefilehoặc -Fvới pyinstaller.

Môi trường của tôi như sau.


Giải quyết vấn đề trong 2 bước

Để giải quyết vấn đề, chúng tôi cần thông báo cụ thể với Pyinstaller rằng chúng tôi có các tệp bổ sung cần được "đóng gói" với ứng dụng.

Chúng tôi cũng cần sử dụng một đường dẫn 'tương đối' để ứng dụng có thể chạy đúng cách khi nó đang chạy dưới dạng Python Script hoặc Frozen EXE.

Như đã nói, chúng ta cần một hàm cho phép chúng ta có các đường dẫn tương đối. Sử dụng chức năng mà Max Posted chúng ta có thể dễ dàng giải quyết vấn đề tương đối.

def img_resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
    try:
        # PyInstaller creates a temp folder and stores path in _MEIPASS
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")

    return os.path.join(base_path, relative_path)

Chúng tôi sẽ sử dụng chức năng trên như thế này để biểu tượng ứng dụng hiển thị khi ứng dụng đang chạy dưới dạng Script HOẶC Frozen EXE.

icon_path = img_resource_path("app/img/app_icon.ico")
root.wm_iconbitmap(icon_path)

Bước tiếp theo là chúng ta cần hướng dẫn Pyinstaller nơi tìm các tệp bổ sung khi nó đang biên dịch để khi ứng dụng được chạy, chúng sẽ được tạo trong thư mục tạm thời.

Chúng tôi có thể giải quyết vấn đề này theo hai cách như được hiển thị trong tài liệu , nhưng cá nhân tôi thích quản lý tệp .spec của riêng mình, vì vậy đó là cách chúng tôi sẽ thực hiện.

Đầu tiên, bạn phải có tệp .spec. Trong trường hợp của tôi, tôi đã có thể tạo ra những gì tôi cần bằng cách chạy pyinstallervới các args bổ sung, bạn có thể tìm thêm args tại đây . Vì điều này, tệp thông số kỹ thuật của tôi có thể hơi khác so với tệp của bạn nhưng tôi sẽ đăng tất cả để tham khảo sau khi tôi giải thích các điểm quan trọng.

added_files về cơ bản là một Danh sách chứa Tuple, trong trường hợp của tôi, tôi chỉ muốn thêm một hình ảnh DUY NHẤT, nhưng bạn có thể thêm nhiều ico, png hoặc jpg bằng cách sử dụng.('app/img/*.ico', 'app/img')Bạn cũng có thể tạo một bộ khác như vậyadded_files = [ (), (), ()]để có nhiều lần nhập

Phần đầu tiên của bộ tuple xác định tệp nào hoặc loại tệp nào bạn muốn thêm cũng như nơi tìm chúng. Hãy coi đây là CTRL + C

Phần thứ hai của tuple nói với Pyinstaller, tạo đường dẫn 'app / img /' và đặt các tệp trong thư mục đó LIÊN QUAN đến bất kỳ thư mục tạm thời nào được tạo khi bạn chạy .exe. Hãy coi đây là CTRL + V

Dưới đâya = Analysis([main... , tôi đã đặtdatas=added_files, ban đầu nó đã từng như vậydatas=[]nhưng chúng tôi muốn đưa ra danh sách các nhập khẩu, tốt, được nhập khẩu để chúng tôi chuyển các nhập khẩu tùy chỉnh của mình.

Bạn không cần phải làm điều này trừ khi bạn muốn có một biểu tượng cụ thể cho EXE, ở cuối tệp thông số kỹ thuật, tôi yêu cầu Pyinstaller đặt biểu tượng ứng dụng của tôi cho exe với tùy chọn icon='app\\img\\app_icon.ico'.

added_files = [
    ('app/img/app_icon.ico','app/img/')
]
a = Analysis(['main.py'],
             pathex=['D:\\Github Repos\\Processes-Killer\\Process Killer'],
             binaries=[],
             datas=added_files,
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          [],
          name='Process Killer',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          upx_exclude=[],
          runtime_tmpdir=None,
          console=True , uac_admin=True, icon='app\\img\\app_icon.ico')

Biên dịch sang EXE

Tôi rất lười; Tôi không thích gõ nhiều thứ hơn tôi phải làm. Tôi đã tạo một tệp .bat mà tôi có thể nhấp vào. Bạn không cần phải làm điều này, mã này sẽ chạy trong một trình bao dấu nhắc lệnh mà không cần nó.

Vì tệp .spec chứa tất cả cài đặt biên dịch & args (hay còn gọi là tùy chọn) của chúng tôi, chúng tôi chỉ cần cung cấp tệp .spec đó cho Pyinstaller.

pyinstaller.exe "Process Killer.spec"

0

Một giải pháp khác là tạo một móc thời gian chạy, móc này sẽ sao chép (hoặc di chuyển) dữ liệu của bạn (tệp / thư mục) vào thư mục mà tệp thực thi được lưu trữ. Hook là một tệp python đơn giản có thể làm mọi thứ, ngay trước khi thực thi ứng dụng của bạn. Để thiết lập nó, bạn nên sử dụng --runtime-hook=my_hook.pytùy chọn của pyinstaller. Vì vậy, trong trường hợp dữ liệu của bạn là một thư mục hình ảnh , bạn nên chạy lệnh:

pyinstaller.py --onefile -F --add-data=images;images --runtime-hook=cp_images_hook.py main.py

Cp_images_hook.py có thể giống như sau:

import sys
import os
import shutil

path = getattr(sys, '_MEIPASS', os.getcwd())

full_path = path+"\\images"
try:
    shutil.move(full_path, ".\\images")
except:
    print("Cannot create 'images' folder. Already exists.")

Trước mỗi lần thực thi, thư mục images sẽ được chuyển đến thư mục hiện tại (từ thư mục _MEIPASS), vì vậy tệp thực thi sẽ luôn có quyền truy cập vào nó. Theo cách đó, không cần phải sửa đổi mã dự án của bạn.

Giải pháp thứ hai

Bạn có thể tận dụng cơ chế runtime-hook và thay đổi thư mục hiện tại, đây không phải là cách tốt theo một số nhà phát triển, nhưng nó hoạt động tốt.

Mã móc có thể được tìm thấy dưới đây:

import sys
import os

path = getattr(sys, '_MEIPASS', os.getcwd())   
os.chdir(path)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.