使用Python在Linux中自动化文件组织的项目。在我知道如何编码之前,我一直想用这种方式来做这个项目。现在我做了,我想改进它更多。
使用的语言: Python。
兼容系统: Linux。
已使用模块:操作系统模块。
它的工作原理:当您将文件保存/移动/复制到一个主目录(例如:下载,Documents...etc)时,它将自动将其移动到其指定的目录中。它将同时使用扩展名和我在文件名开头提供的2/3字母代码。一旦我打开电脑,它就会在后台运行。
这个程序只在文件上工作,而不是目录(我通常没有它们,当我这样做的时候,我想亲自去做)。
提前谢谢你。
FileOrganizer.py:
#!/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:
#!/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:
#!/bin/bash
nohup python3 -u /home/hama/Codes/Python/FileAutomationV1.0/FileOrganizer.py &发布于 2020-05-03 18:23:33
除了其他人已经说过的话之外,最重要的是,您正在为更改进行投票,这是浪费的。
在Linux上,正确的解决方案是使用一些绑定到inotify API,以便您可以在所监视的目录上接收IN_CLOSE_WRITE和IN_MOVED_TO事件。这样,您的监视进程就可以无限期地休眠,当有工作要做时,内核将唤醒它。
发布于 2020-05-03 13:02:19
我同意回答中@AlexPovel提到的所有要点,我不打算重复它们。
让我感到奇怪的是,这个类名为FileOrganizer,但它所做的只是为处理路径提供了方便的函数。它没有显式地组织您的文件!它作为独立代码留在类之外。
我会把移动代码作为课堂的一部分。这意味着您的全局文件类型数据结构可能应该是类属性。之后你可以做:
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+),它只在命令完成后才返回。
该方法可以如下所示:
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模块将其移动到日志文件中。
https://codereview.stackexchange.com/questions/241644
复制相似问题