首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Linux上使用Python的文件自动化

Linux上使用Python的文件自动化
EN

Code Review用户
提问于 2020-05-03 07:20:38
回答 2查看 1.9K关注 0票数 8

使用Python在Linux中自动化文件组织的项目。在我知道如何编码之前,我一直想用这种方式来做这个项目。现在我做了,我想改进它更多。

使用的语言: Python。

兼容系统: Linux。

已使用模块:操作系统模块。

它的工作原理:当您将文件保存/移动/复制到一个主目录(例如:下载,Documents...etc)时,它将自动将其移动到其指定的目录中。它将同时使用扩展名和我在文件名开头提供的2/3字母代码。一旦我打开电脑,它就会在后台运行。

这个程序只在文件上工作,而不是目录(我通常没有它们,当我这样做的时候,我想亲自去做)。

问题

  1. 我的代码可读性如何?
  2. 有什么我不知道的逻辑错误吗?
  3. 如何改进?
  4. 有没有更好的方法来解决这个问题?
  5. 总的来说,你如何评价它的10个?

提前谢谢你。

FileOrganizer.py:

代码语言:javascript
复制
#!/usr/bin/env python

import os
import time
import os.path
from random import randint
from ExtraInfo import types, locations, docs, working_directories


class FileOrganizer:

    def __init__(self, directory_path):
        self.directory_path = directory_path

    def path_maker(self, root, file_name):
        """(str, str) -> str

        Returns a string containing the full path of a file,
        from root of the file and its name.

        >>> path_maker("/home/hama/Downloads", "area.cpp")
        "/home/hama/Downloads/area.cpp"
        >>> path_maker("/home/hama/Downloads/", "FuzzBuzz.py")
        "/home/hama/Downloads/FuzzBuzz.py"
        """

        return os.path.join(root, file_name)

    def extension_finder(self, path):
        """(str) -> str

        Takes in a string of full path of a file. If exists,
        returns a string of its extension, else returns False.

        >>> extension_finder("/home/hama/Downloads/area.cpp")
        ".cpp"
        >>> extension_finder("/home/hama/Downloads/FuzzBuzz.py")
        ".py"
        """

        if os.path.exists(path):
            if os.path.isfile(path):
                return os.path.splitext(path)[1]
        return False

    def category_selector(self, extension):
        """(str) -> str

        Takes in a string of an extension of a file. If not False,
        returns the category of the extension, else returns False.

        Precondition: The extension must be in one of the categories.

        >>> category_selector(".cpp")
        "programming-files"
        >>> category_selector(".mp4")
        "video"
        """

        if extension != False:
            for category in types:
                if extension in types[category]:
                    return category
                    break
            return False

    def get_prefix(self, path):
        """(str) -> str

        Takes in a string of full path of a file. If it is one of the doc
        categories returns the first 3 characters of name of the file, else 2.

        Precondition: A prefix of a specific directory should be provided
        at the beginning of the name of the file.

        >>> get_prefix("/home/hama/Downloads/umaMath-week11.pdf")
        "uma"
        >>> get_prefix("/home/hama/Downloads/pyFuzzBuzz.py")
        "py"
        """

        prefix = os.path.basename(path)
        if self.category_selector(self.extension_finder(path)) not in docs:
            return prefix[:2]
        else:
            return prefix[:3]

    def get_original_name(self, path):
        """(str) -> str

        Takes in a string of full path of a file. returns a string of
        the original file name without any prefix.

        Precondition: A prefix of a specific directory should be provided
        at the beginning of the name of the file.

        >>> get_original_name("/home/hama/Downloads/umaMath-week11.pdf")
        "Math-week11.pdf"
        >>> get_original_name("/home/hama/Downloads/pyFuzzBuzz.py")
        "FuzzBuzz.py"
        """

        file_name = os.path.basename(path)
        if self.category_selector(self.extension_finder(path)) not in docs:
            return file_name[2:]
        else:
            return file_name[3:]

    def random_name_generator(self, path):
        """(str) -> str

        Takes in a string of full path of a file. Generates a random
        integer at the end of the name of the file, the returns the new name.

        >>> random_name_generator("/home/hama/Downloads/umaMath-week11.pdf")
        "Math-week11.pdf"
        >>> random_name_generator("/home/hama/Downloads/pyFuzzBuzz.py")
        "FuzzBuzz.py"
        """

        file_name = os.path.splitext(path)[0]
        extension = os.path.splitext(path)[1]
        return f"""{file_name}-{randint(1, 250) % randint(1, 250)}{extension}"""

    def copy(self, file_source, destination_root):
        """(str, str) -> str

        Returns a string containing the full path of the newly moved file,
        from a full path of a file and root of the destination.

        Note: If a file with the same name already exists, a new name will be generated.

        >>> copy("/home/hama/Downloads/area.cpp", "/home/hama/Codes/C++/")
        "/home/hama/Codes/C++/area.cpp"
        >>> copy("/home/hama/Downloads/FuzzBuzz.py", "/home/hama/Codes/Python/")
        "/home/hama/Codes/Python/FuzzBuzz.py"
        """

        if not os.path.exists(self.path_maker(destination_root, self.get_original_name(file_source))):
            file_name = os.path.basename(file_source)
            file_destination = self.path_maker(
                destination_root, self.get_original_name(file_source))
            os.system(f"cp -pa {file_source} {file_destination}")
            return file_destination
        else:
            file_name = self.random_name_generator(self.path_maker(
                destination_root, self.get_original_name(file_source)))
            file_destination = self.path_maker(destination_root, file_name)
            os.system(f"cp -pa {file_source} {file_destination}")
            return file_destination


# Activated on these directories
paths = [FileOrganizer(f"{directory}") for directory in working_directories]
while True:
    for path in paths:
        # Get the files and directories in the root directory.
        for root, directories, files in os.walk(path.directory_path):
            root, directories, files = root, directories, files
            break

        # List the files in the directory
        list_of_files = []
        for file in files:
            list_of_files.append(path.path_maker(root, file))

        # Loop through the files and copy each one of them.
        proccess = True
        for file in list_of_files:
            if proccess:
                current_file = file

                file_category = path.category_selector(
                    path.extension_finder(current_file))
                if file_category in locations:
                    if locations[file_category].get(path.get_prefix(current_file)) != None:
                        destination_root = locations[file_category].get(
                            path.get_prefix(current_file))

                        # Check if there is a whitespace in the path, cause it cause infinite loop.
                        if not (" " in current_file):
                            new_file_destination = path.copy(
                                current_file, destination_root)
                        else:
                            continue
                        if os.path.exists(new_file_destination):
                            os.remove(current_file)

                        # Check if the file is moved and the proccess is done, otherwise wait until it is done.
                        if not os.path.exists(current_file) and os.path.exists(new_file_destination):
                            proccess = True
                        else:
                            proccess = False
                            while not proccess:
                                if not os.path.exists(current_file) and os.path.exists(new_file_destination):
                                    proccess = True
                                else:
                                    proccess = False
                                time.sleep(10)

        time.sleep(5)

# By: Hama
# Software Engineer to be.

ExtraInfo.py:

代码语言:javascript
复制
#!/usr/bin/env python
types = {

    'audio': ['.wpl', '.wma', '.wav', '.ogg', '.mpa', '.mp3', '.mid', '.midi', '.cda', '.aif'],

    'database': ['.csv', '.dat', '.db', '.dbf', 'log', '.mdb', '.sav', 'sqlite', '.sql', '.tar', '.xml'],

    'fonts': ['.fnt', '.fon', '.otf', '.ttf'],

    'image': ['.ai', '.bmp', '.gif', '.ico', '.jpeg', '.jpg', '.png', '.ps', '.psd', '.svg', '.tif', '.tiff'],

    'doc-presentation': ['.key', '.odp', '.pps', '.ppt', '.pptx'],

    'internet': ['.asp', '.srt', '.aspx', '.cer', '.cfm', '.cgi', '.htm', '.jsp', '.part', '.rss', '.xhtml', '.torrent'],

    'programming-files': ['.c', '.class', '.cpp', '.cs', '.h', '.java', '.pl', '.sh', '.swift', '.vb', '.php', '.html', '.css', '.js', '.py'],

    'doc-spreadsheet': ['.ods', '.xls', '.xlsm', '.xlsx'],

    'video': ['.3g2', '.3gp', '.avi', '.flv', '.h264', '.264', '.m4v', '.mkv', '.mov', '.mp4', '.mpg', '.mpeg', '.rm', '.swf', '.vob', '.wmv'],

    'doc-word': ['.doc', '.docx', '.odt', '.rtf', '.tex', '.wpd'],

    'doc-pdf': ['.pdf', '.epub', '.mobi'],

    'text': ['.txt']

}

locations = {

    'audio': {'na': '/home/hama/Music/Others'},

    'database': {'na': '/home/hama/Documents/Others/Database'},

    'fonts': {'na': '/home/hama/Documents/Others/Fonts'},

    'internet': {'na': "/home/hama/Documents/Others/Internet-Related"},

    'image': {'my': '/home/hama/Pictures/Myself', 'ot': '/home/hama/Pictures/Others', 'wa': '/home/hama/Pictures/Wallpapers'},

    'video': {'my': '/home/hama/Videos/Myself', 'ot': '/home/hama/Videos/Others', 'mv': '/home/hama/Videos/Movies', 'tu': '/home/hama/Videos/Tutorials', 'se': '/home/hama/Videos/Series'},

    'programming-files': {'ot': '/home/hama/Codes/Others', 'wb': '/home/hama/Codes/Web', 'cp': '/home/hama/Codes/C++', 'py': '/home/hama/Codes/Python'},

    'doc-spreadsheet': {'bop': "/home/hama/Documents/Books/Programming-Books", 'bon': "/home/hama/Documents/Books/Novels", 'boo': "/home/hama/Documents/Books/Others", 'duc': "/home/hama/Documents/Documents/Spreadsheet", 'tmp': "/home/hama/Documents/Temp", 'uot': "/home/hama/Documents/UKH/Undergraduate-I/Other-Documents", 'uma': "/home/hama/Documents/UKH/Undergraduate-I/Semester-II/Engineering-Mathematics-II", 'udl': "/home/hama/Documents/UKH/Undergraduate-I/Semester-II/Introduction-to-Digital-Logic-&-Electronics", 'usp': "/home/hama/Documents/UKH/Undergraduate-I/Semester-II/Structured-Programming", 'uen': "/home/hama/Documents/UKH/Undergraduate-I/Semester-II/English-Composition-II"},

    'doc-presentation': {'bop': "/home/hama/Documents/Books/Programming-Books", 'bon': "/home/hama/Documents/Books/Novels", 'boo': "/home/hama/Documents/Books/Others", 'duc': "/home/hama/Documents/Documents/Presentations", 'tmp': "/home/hama/Documents/Temp", 'uot': "/home/hama/Documents/UKH/Undergraduate-I/Other-Documents", 'uma': "/home/hama/Documents/UKH/Undergraduate-I/Semester-II/Engineering-Mathematics-II", 'udl': "/home/hama/Documents/UKH/Undergraduate-I/Semester-II/Introduction-to-Digital-Logic-&-Electronics", 'usp': "/home/hama/Documents/UKH/Undergraduate-I/Semester-II/Structured-Programming", 'uen': "/home/hama/Documents/UKH/Undergraduate-I/Semester-II/English-Composition-II"},

    'doc-word': {'bop': "/home/hama/Documents/Books/Programming-Books", 'bon': "/home/hama/Documents/Books/Novels", 'boo': "/home/hama/Documents/Books/Others", 'duc': "/home/hama/Documents/Documents/Word", 'tmp': "/home/hama/Documents/Temp", 'uot': "/home/hama/Documents/UKH/Undergraduate-I/Other-Documents", 'uma': "/home/hama/Documents/UKH/Undergraduate-I/Semester-II/Engineering-Mathematics-II", 'udl': "/home/hama/Documents/UKH/Undergraduate-I/Semester-II/Introduction-to-Digital-Logic-&-Electronics", 'usp': "/home/hama/Documents/UKH/Undergraduate-I/Semester-II/Structured-Programming", 'uen': "/home/hama/Documents/UKH/Undergraduate-I/Semester-II/English-Composition-II"},

    'doc-pdf': {'bop': "/home/hama/Documents/Books/Programming-Books", 'bon': "/home/hama/Documents/Books/Novels", 'boo': "/home/hama/Documents/Books/Others", 'duc': "/home/hama/Documents/Documents/PDF", 'tmp': "/home/hama/Documents/Temp", 'uot': "/home/hama/Documents/UKH/Undergraduate-I/Other-Documents", 'uma': "/home/hama/Documents/UKH/Undergraduate-I/Semester-II/Engineering-Mathematics-II", 'udl': "/home/hama/Documents/UKH/Undergraduate-I/Semester-II/Introduction-to-Digital-Logic-&-Electronics", 'usp': "/home/hama/Documents/UKH/Undergraduate-I/Semester-II/Structured-Programming", 'uen': "/home/hama/Documents/UKH/Undergraduate-I/Semester-II/English-Composition-II"},

    'text': {'tx': "/home/hama/Documents/Documents/PDF"}
}

docs = ['doc-spreadsheet', 'doc-presentation', 'doc-word', 'doc-pdf']

working_directories = ["/home/hama/Downloads/", "/home/hama/Documents/", "/home/hama/Codes/",
                    "/home/hama/Desktop/", "/home/hama/Music/", "/home/hama/Pictures/", "/home/hama/Videos/"]

script.sh:

代码语言:javascript
复制
#!/bin/bash
nohup python3 -u /home/hama/Codes/Python/FileAutomationV1.0/FileOrganizer.py &
EN

回答 2

Code Review用户

发布于 2020-05-03 18:23:33

除了其他人已经说过的话之外,最重要的是,您正在为更改进行投票,这是浪费的。

在Linux上,正确的解决方案是使用一些绑定到inotify API,以便您可以在所监视的目录上接收IN_CLOSE_WRITEIN_MOVED_TO事件。这样,您的监视进程就可以无限期地休眠,当有工作要做时,内核将唤醒它。

票数 8
EN

Code Review用户

发布于 2020-05-03 13:02:19

我同意回答@AlexPovel提到的所有要点,我不打算重复它们。

让我感到奇怪的是,这个类名为FileOrganizer,但它所做的只是为处理路径提供了方便的函数。它没有显式地组织您的文件!它作为独立代码留在类之外。

我会把移动代码作为课堂的一部分。这意味着您的全局文件类型数据结构可能应该是类属性。之后你可以做:

代码语言:javascript
复制
file_organizers = [FileOrganizer(path) for path in paths]
while True:
    for file_organizer in file_organizers:
        file_organizer.organize()
    time.sleep(5)

目前,您还在运行一个循环,直到文件复制完成,如果文件还在,每10秒检查一次。我要么选择全异步 (并跟踪当前正在复制的文件),要么使用subprocess.run (Python3.5+),它只在命令完成后才返回。

该方法可以如下所示:

代码语言:javascript
复制
import subprocess

class FileOrganizer:

    ...

    def move(self, file, destination):
        ... # get the right names
        subprocess.run(["cp", "-pa", file, destination])
        if os.path.exists(destination):
            os.remove(file)
        else:
            print(f"Moving {file} failed.")
        return destination

    def organize(self):
        # Get the files and directories in the root directory.
        root, directories, files = next(os.walk(self.directory_path))
        root = Path(root)
        # List the files in the directory
        files = (root.joinpath(file) for file in files if " " not in file)

        # Loop through the files and copy each one of them.
        for file in files:
            file_category = self.category_selector(file.suffix)
            location = self.locations.get(file_category)
            if location is None:
                print("{file_category} is not a valid category")
                continue
            prefix = self.get_prefix(file)
            destination_root = location.get(prefix)
            if destination_root is None:
                print(f"{prefix} is not a valid prefix")
                continue
            self.move(file, destination_root)

请注意,我添加了一些调试输出,以便更容易地查看脚本正在做什么。您可能希望最终使用logging模块将其移动到日志文件中。

票数 7
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/241644

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档