Проверка состояния USB-накопителя и функция удаления файлов

У меня есть функция под названием USB(), что будет понаблюдайте за вставкой usb-флешки и удалите файлы внутри нее, если они есть:

import os
import shutil

# 1. Check and clean USB

def USB():
    usb_inserted = os.path.isdir("F:") # <-- returns boolean...checks whether a directory exists

    if usb_inserted == False:
        print("nnUSB stick is not plugged in. Waiting for connection...")

        while usb_inserted == False: # wait

            """ updating variable, because it takes only the return value of function 'isdir()'
             and stays the same regardless of the fact, that 'isdir()' changed """
            usb_inserted = os.path.isdir("F:") 
            continue
            
    SECURITY_FILE = "System Volume Information"

    if os.listdir("F:") == [SECURITY_FILE] or os.listdir("F:") == []: # if list of files contains only the security file (is empty)
        print("nUSB flash is already empty.") # send a message and continue

    else:
        files = os.listdir("F:") # list of names of files in the usb flash, that will be deleted

        if SECURITY_FILE in files:

            """ taking out the security file from the list, because attempting to delete it causes
            'PermissionError [WinError 5]' exception """
            files.remove(SECURITY_FILE) 

        for file in files: # Loop through the file list
            
            if os.path.isfile(f"F:\{file}"): # if it's a file
                os.remove(f"F:\{file}") # Delete the file

            elif os.path.isdir(f"F:\{file}"): # if it's a directory/folder
                shutil.rmtree(f"F:\{file}") # remove the folder

        print("nAll files/folders are deleted from USB.")

USB()

Есть ли что-нибудь, что можно улучшить с точки зрения более чистого кода или вещей, которые я мог пропустить во время тестирования?

3 ответа
3

Логические проверки

Вместо того, чтобы делать:

if usb_inserted == False:
    # do something

использовать

if not usb_inserted:
    # do something

while not usb_inserted

Этот цикл while будет обрабатывать вызов файловой системы, чтобы проверить, существует ли диск. Вместо этого я бы проверял раз в несколько секунд:

from time import sleep

def wait_for_usb():
    while True:
        if os.path.isdir('F:'):
            break
        else:
            # give user notification it's still waiting
            print('Detecting...')
            time.sleep(2)

Проверка содержимого списка

Чтобы проверить пустой список, вы можете полагаться на его истинность вместо явной проверки на равенство:

# instead of this:
if os.listdir("F:") == []:
    # do something

# do this
if not os.listdir('F:'):
    # do something

Более того, было бы лучше проделать эту операцию только один раз:

# This might be a better check for the security file
def only_contains_security_file(contents):
    return len(contents) == 1 and contents[0] == "System Volume Information"


# only grab contents once
contents = os.listdir('F:')

if not contents or only_contains_security_file(contents):
    print("nUSB flash is already empty.")

Итерация по файлам

Поскольку вы просто хотите прогуляться по дороге на высшем уровне, вы можете использовать os.scandir вместо повторения os.listdir. У этого есть несколько преимуществ. Во-первых, он не объединяет все в list (недостаток в том, что os.walk есть для этого использования) и что он автоматически позволяет вам проверять типы:

for item in os.scandir('F:'):
    if item.name.endswith("System Volume Information"):
        continue
    elif item.is_file():
        os.remove(item.path)
    else:
        shutil.rmtree(item.path)
        

Это также полезно, если ваш USB-порт заполнен множеством файлов с длинными именами.

Вам также не нужно проверять, пуст ли он, ваш цикл просто пропустит все, если это так.

Добавление if __name__ == "__main__" сторожить

Это полезно для сценариев, которые вы, возможно, захотите запустить, но также хотите импортировать что-то из. С этим защитным устройством, если вы импортируете что-то из модуля usb из другого скрипта Python, он не выполнит ваш скрипт. Это приятно, учитывая, что у вас бесконечный цикл:

def usb():
    # your code

if __name__ == "__main__":
    usb()

Итак, в целом:

import os
import shutil
from time import sleep


def wait_for_usb():
    print("Waiting for usb at F:")

    while True:
        if os.path.isdir('F:'):
            break
        else:
            print("Detecting...")
            time.sleep(2)


def usb():
     wait_for_usb()

     for item in os.scandir('F:'):
        if item.name.endswith("System Volume Information"):
            print('Skipping system info file')
            continue
        elif item.is_file():
            print(f"Removing file {item.path}")
            os.remove(item.path)
        else:
            print(f"Removing directory {item.path}")
            shutil.rmtree(item.path)


     print('USB is now empty')


if __name__ == "__main__":
    usb()

  • 1. Я не согласен с wait_for_usb() функция, потому что что, если usb был вставлен во время этой 2-секундной задержки перед следующей проверкой? Чтобы распознать его, потребуется немного больше времени (особенно на моем картофельном ПК, где окнам требуется больше времени для распознавания устройств), но моя версия попадает туда сразу же, когда подключается usb.

    — user394299


  • 1

    @ user394299 Я имею в виду, это 2 секунды, но если ждать слишком долго, вы можете либо полностью отказаться от сна, либо заставить его спать на меньшее время

    — C.Nivs

  • 10

    Ожидания, которые занимают все ядро ​​ЦП только для отслеживания изменений, обычно считаются ужасными. Полагаю, этого было бы достаточно для простой демонстрации кода в школе, но если бы я увидел это в производственном приложении, я бы очень плохо подумал об авторе. У компьютера есть другие дела; пользователи ненавидят, когда программа использует все ядро ​​только для того, чтобы дождаться чего-то неподконтрольного ей. В идеале вы хотите зарегистрироваться в ОС для события, но если вы не можете, по крайней мере, сделайте паузу на полсекунды или более между проверками. Сведите к минимуму время процессора.

    — Корродиас


  • 4

    @ user394299 На самом деле любая реализация ожидания USB плохая, так что они, вероятно, имеют в виду и то, и другое. Моя — это усовершенствование, позволяющее избежать ударов цикла по ЦП, что снижает производительность. Райндерин прав, есть способы сделать это лучше, чем качество продукции.

    — C.Nivs

  • 5

    @ user394299 Оба неоптимальны, да, но ожидание некоторого времени между проверками значительно легче при использовании ресурсов, чем жесткий цикл. Я ожидаю, что лучшая производительность будет достигнута при регистрации обработчика событий вставки диска в Win32 API, но это ужасно сложно сделать в Python. В этом вопросе, кажется, есть некоторые подробности. stackoverflow.com/questions/38689090

    — Корродиас

Решение производственного уровня вообще не будет иметь цикла опроса и будет полагаться на ловушку уведомления об изменении файловой системы. Есть много, много способов делать это с разной степенью портативности и простоты использования; на вашем месте я бы использовал что-нибудь портативное и готовое, например сторожевая собака.

    Рекомендуется следовать PEP8 для удобочитаемости и ремонтопригодности. Код нарушает многие правила.

    Пустые строки

    USB над ним есть только одна пустая строка.

    Пустые строки

    Окружите определения функций и классов верхнего уровня двумя пустыми строками.

    Длина линии

    Максимальная длина строки

    Ограничьте все строки до 79 символов.

    Для потоковых длинных блоков текста с меньшим количеством структурных ограничений (строк документации или комментариев) длина строки должна быть ограничена 72 символами.

    Есть много строк, которые содержат более 79 символов.

    Константы

    Похоже, что функция использует только одну константу: SECURITY_FILE

    Константы

    Константы обычно определяются на уровне модуля и пишутся заглавными буквами с подчеркиванием, разделяющим слова. Примеры включают MAX_OVERFLOW и TOTAL.

    Двигаться SECURITY_FILE в верхнюю часть модуля. Хотя его, возможно, никогда не потребуется обновлять, если потребуется изменение, его будет легче найти, а не искать в файле.

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

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