Сохранение временных файлов PDF на USB-накопителе из внешнего приложения

Вот функция save_document(), это опрашивает нажатие Extract PDF кнопка во внешней программе и сохраняет файл PDF в формате tmp на USB-накопитель.

import time

import os
import shutil

def save_document():
    print("nnPreparing to save the document...", end = "r")

    TEMP_PDF_DIR = "C:/Users/TUN/tp3/workspace/tmp" # temporary pdfs are stored in this directory

    while not os.listdir(TEMP_PDF_DIR): # wait until the "Extract PDF" button is pressed and a file will be created in directory TEMP_PDF_DIR
        time.sleep(0.5)
        continue

    file_path = "C:/Users/TUN/tp3/workspace/tmp" + "/" + os.listdir(TEMP_PDF_DIR)[0]

    shutil.move(file_path, find_drive_id()) # move the file in the USB drive directory 

    print("Document PDF was saved successfully.")

И find_drive() функция, которая ищет запоминающее устройство с заданным серийный номер и возвращает его путь (буква пути, например D :, F: и т. д.)

import wmi

def find_drive_id():
    local_machine_connection = wmi.WMI()

    DRIVE_SERIAL_NUMBER = "88809AB5" # serial number is like an identifier for a storage device determined by system

    '''.Win32.LogicalDisk returns list of wmi_object objects, which include information
    about all storage devices and discs (C:, D:)'''

    for storage_device in local_machine_connection.Win32_LogicalDisk():
        if storage_device.VolumeSerialNumber == DRIVE_SERIAL_NUMBER:
            return storage_device.DeviceID

    return False

Есть ли лучший способ сохранить только что созданный временный файл PDF?

Кроме того, меня беспокоит цикл опроса … Я считаю, что есть более элегантный подход.

1 ответ
1

Общие комментарии

Лично опрос кажется нормальным, стандартный способ сделать это — использовать watchdog. Я просто укажу на некоторые моменты, которые мне кажутся странными в вашем коде.


imports

Распространенный способ в Python — разделить импорт на три части: встроенные модули, модули сообщества и локальные. Так что это

import time

import os
import shutil

Действительно должно быть это

import time
import os
import shutil

Потому что time, os а также shutil все живут в стандартная библиотека.


descriptive function names

Называть это сложно, но очень важно хорошо подумать о том, как вы называете вещи; особенно функции, классы и модули. Основная причина, почему

save_document(): а также find_drive_id()

Плохие имена потому, что они не делают то, что говорят. Сохранить документ не сохраняет документ, а перемещает уже сохранено документ в другую папку. сходным образом find_drive_id не находит идентификатор диска, но возвращает путь к диску.


hardcoded paths

Это сделка 2 по цене 1. Первые пути лучше обрабатывать с помощью pathlib модуль (опять же в стандартной библиотеке). Кроме того, мы используем этот путь несколько раз, поэтому он должен быть извлечен в его собственную глобальную константу.

import pathlib

DIRECTORY_TO_WATCH = pathlib.PureWindowsPath("c:/Users/TUN/tp3/workspace/tmp")

сходным образом DRIVE_SERIAL_NUMBER = "88809AB5" вероятно, тоже должна быть глобальной константой.


docstrings

Тройные кавычки обычно зарезервированы для строки документации. Вдобавок это

'''.Win32.LogicalDisk returns list of wmi_object objects, which include information
about all storage devices and discs (C:, D:)'''

является скорее комментарием, чем цитатой, и может быть преобразован в #. Кроме того, вы должны добавить строки документации, объясняющие, что делает каждая функция.


for else

Это действительно мелочь, но мы можем написать

for storage_device in local_machine_connection.Win32_LogicalDisk():
    if storage_device.VolumeSerialNumber == DRIVE_SERIAL_NUMBER:
        return storage_device.DeviceID
else:
    return False

Что я нахожу более понятным для чтения. Если мы не сломаемся или не вернемся в for loop в else оговорка срабатывает. Вы также можете подумать о else в качестве then.


if __name__ == "__main__":

Поместите те части вашего кода, которые требуют выполнения, за if __name__ == "__main__": сторожить. Таким образом, вы можете импортировать этот модуль python из других мест, если хотите, а защита предотвращает случайный запуск основного кода при каждом импорте.

Пример кода

Вот макет того, как реализация сторожевого пса could Смотреть. Обратите внимание, что я работаю в Linux и у меня нет возможности проверить детали, если все реализовано правильно. Однако это должно быть хорошей отправной точкой =)

import time
import pathlib
import shutil

import wmi
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler

DIRECTORY_TO_WATCH = pathlib.PureWindowsPath("c:/Users/TUN/tp3/workspace/tmp")
# serial number is like an identifier for a storage device determined by system
DRIVE_SERIAL_NUMBER = "88809AB5"
SLEEP_TIME = 5


class Watcher:
    DIRECTORY_TO_WATCH = DIRECTORY_TO_WATCH
    SLEEP_TIME = SLEEP_TIME

    def __init__(self):
        self.observer = Observer()

    def run(self):
        event_handler = Handler()
        self.observer.schedule(event_handler, self.DIRECTORY_TO_WATCH, recursive=True)
        self.observer.start()
        try:
            while True:
                time.sleep(self.SLEEP_TIME)
        except:
            self.observer.stop()
            print("Error")

        self.observer.join()


class Handler(FileSystemEventHandler):
    @staticmethod
    def on_any_event(event):
        if event.is_directory:
            return None

        elif event.event_type == "created":
            # Take any action here when a file is first created.
            # move the file in the USB drive directory
            file_path = pathlib.PureWindowsPath(event.src_path)
            shutil.move(file_path, get_usb_path())
            print("Document PDF was saved successfully.")


def get_usb_path():
    local_machine_connection = wmi.WMI()
    # Win32.LogicalDisk returns list of wmi_object objects, which include
    # information about all storage devices and discs (C:, D:)
    for storage_device in local_machine_connection.Win32_LogicalDisk():
        if storage_device.VolumeSerialNumber == DRIVE_SERIAL_NUMBER:
            return storage_device.DeviceID
    else:
        return False


if __name__ == "__main__":
    w = Watcher()
    w.run()

    Добавить комментарий

    Ваш адрес email не будет опубликован. Обязательные поля помечены *