17 Bulk File Rename Tool Python
18 RP 이름 바꾸기
RP Renamer는 Python과 PyQt5로 구축된 대량 파일 이름 바꾸기 도구입니다.
18.1 애플리케이션 실행
RP Renamer를 실행하려면 소스 코드를 다운로드해야 합니다. 그런 다음 터미널이나 명령줄 창을 열고 다음 단계를 실행합니다.
- Python 가상 환경을 생성하고 활성화합니다.
$ cd rprename_project/
$ python3 -m venv ./venv
$ source venv/bin/activate
(venv) $- 종속성을 설치합니다.
(venv) $ pip install -r requirements.txt- 애플리케이션을 실행합니다.
(venv) $ python3 rprenamer.py참고: 이 애플리케이션은 Python 3.8.5 및 PyQt 5.15.2로 코딩 및 테스트되었습니다.
18.2 출시 내역
- 0.1.0
- 진행중인 작업
18.3 저자 소개
레오다니스 포조 라모스 – (lpozo78?) – leodanis@realpython.com
18.4 파일: source_code_final/rprename/__init__.py
이 모듈은 RP Renamer 기본 창을 제공합니다.
# -*- coding: utf-8 -*-
"""This module provides the RP Renamer main window."""
__version__ = "0.1.0"18.5 파일: source_code_final/rprename/app.py
이 모듈은 RP Renamer 애플리케이션을 제공합니다.
# -*- coding: utf-8 -*-
"""This module provides the RP Renamer application."""
import sys
from PyQt5.QtWidgets import QApplication
from .views import Window
def main():
# Create the application
app = QApplication(sys.argv)
# Create and show the main window
win = Window()
win.show()
# Run the event loop
sys.exit(app.exec())18.6 파일: source_code_final/rprename/rename.py
이 모듈은 여러 파일의 이름을 바꿀 수 있는 Renamer 클래스를 제공합니다.
# -*- coding: utf-8 -*-
"""This module provides the Renamer class to rename multiple files."""
import time
from pathlib import Path
from PyQt5.QtCore import QObject, pyqtSignal
class Renamer(QObject):
# Define custom signals
progressed = pyqtSignal(int)
renamedFile = pyqtSignal(Path)
finished = pyqtSignal()
def __init__(self, files, prefix):
super().__init__()
self._files = files
self._prefix = prefix
def renameFiles(self):
for fileNumber, file in enumerate(self._files, 1):
newFile = file.parent.joinpath(
f"{self._prefix}{str(fileNumber)}{file.suffix}"
)
file.rename(newFile)
time.sleep(0.1) # Comment this line to rename files faster.
self.progressed.emit(fileNumber)
self.renamedFile.emit(newFile)
self.progressed.emit(0) # Reset the progress
self.finished.emit()18.7 파일: source_code_final/rprename/ui/__init__.py
이 모듈은 RP Renamer GUI를 제공합니다.
# -*- coding: utf-8 -*-
"""This module provides the RP Renamer GUI."""18.8 파일: source_code_final/rprename/ui/window.py
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'window.ui'
#
# Created by: PyQt5 UI code generator 5.14.1
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Window(object):
def setupUi(self, Window):
Window.setObjectName("Window")
Window.resize(720, 480)
self.gridLayout = QtWidgets.QGridLayout(Window)
self.gridLayout.setObjectName("gridLayout")
self.label = QtWidgets.QLabel(Window)
self.label.setMinimumSize(QtCore.QSize(0, 15))
self.label.setMaximumSize(QtCore.QSize(16777215, 15))
self.label.setObjectName("label")
self.gridLayout.addWidget(self.label, 0, 0, 1, 3)
self.dirEdit = QtWidgets.QLineEdit(Window)
self.dirEdit.setMinimumSize(QtCore.QSize(0, 30))
self.dirEdit.setMaximumSize(QtCore.QSize(16777215, 30))
self.dirEdit.setReadOnly(True)
self.dirEdit.setObjectName("dirEdit")
self.gridLayout.addWidget(self.dirEdit, 1, 0, 1, 2)
self.loadFilesButton = QtWidgets.QPushButton(Window)
self.loadFilesButton.setMinimumSize(QtCore.QSize(0, 30))
self.loadFilesButton.setMaximumSize(QtCore.QSize(16777215, 30))
self.loadFilesButton.setObjectName("loadFilesButton")
self.gridLayout.addWidget(self.loadFilesButton, 1, 2, 1, 1)
self.splitter = QtWidgets.QSplitter(Window)
self.splitter.setOrientation(QtCore.Qt.Horizontal)
self.splitter.setObjectName("splitter")
self.layoutWidget = QtWidgets.QWidget(self.splitter)
self.layoutWidget.setObjectName("layoutWidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.layoutWidget)
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.verticalLayout.setObjectName("verticalLayout")
self.label_2 = QtWidgets.QLabel(self.layoutWidget)
font = QtGui.QFont()
font.setBold(True)
font.setWeight(75)
self.label_2.setFont(font)
self.label_2.setObjectName("label_2")
self.verticalLayout.addWidget(self.label_2)
self.srcFileList = QtWidgets.QListWidget(self.layoutWidget)
self.srcFileList.setObjectName("srcFileList")
self.verticalLayout.addWidget(self.srcFileList)
self.layoutWidget1 = QtWidgets.QWidget(self.splitter)
self.layoutWidget1.setObjectName("layoutWidget1")
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.layoutWidget1)
self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.label_3 = QtWidgets.QLabel(self.layoutWidget1)
font = QtGui.QFont()
font.setBold(True)
font.setWeight(75)
self.label_3.setFont(font)
self.label_3.setObjectName("label_3")
self.verticalLayout_2.addWidget(self.label_3)
self.dstFileList = QtWidgets.QListWidget(self.layoutWidget1)
self.dstFileList.setObjectName("dstFileList")
self.verticalLayout_2.addWidget(self.dstFileList)
self.gridLayout.addWidget(self.splitter, 2, 0, 1, 3)
self.label_4 = QtWidgets.QLabel(Window)
self.label_4.setMinimumSize(QtCore.QSize(0, 15))
self.label_4.setMaximumSize(QtCore.QSize(16777215, 15))
self.label_4.setObjectName("label_4")
self.gridLayout.addWidget(self.label_4, 3, 0, 1, 3)
self.prefixEdit = QtWidgets.QLineEdit(Window)
self.prefixEdit.setMinimumSize(QtCore.QSize(0, 30))
self.prefixEdit.setMaximumSize(QtCore.QSize(16777215, 30))
self.prefixEdit.setObjectName("prefixEdit")
self.gridLayout.addWidget(self.prefixEdit, 4, 0, 1, 1)
self.extensionLabel = QtWidgets.QLabel(Window)
self.extensionLabel.setMinimumSize(QtCore.QSize(0, 30))
self.extensionLabel.setMaximumSize(QtCore.QSize(16777215, 30))
self.extensionLabel.setObjectName("extensionLabel")
self.gridLayout.addWidget(self.extensionLabel, 4, 1, 1, 1)
self.renameFilesButton = QtWidgets.QPushButton(Window)
self.renameFilesButton.setMinimumSize(QtCore.QSize(0, 30))
self.renameFilesButton.setMaximumSize(QtCore.QSize(16777215, 30))
self.renameFilesButton.setObjectName("renameFilesButton")
self.gridLayout.addWidget(self.renameFilesButton, 4, 2, 1, 1)
self.progressBar = QtWidgets.QProgressBar(Window)
self.progressBar.setProperty("value", 0)
self.progressBar.setObjectName("progressBar")
self.gridLayout.addWidget(self.progressBar, 5, 0, 1, 3)
self.retranslateUi(Window)
QtCore.QMetaObject.connectSlotsByName(Window)
def retranslateUi(self, Window):
_translate = QtCore.QCoreApplication.translate
Window.setWindowTitle(_translate("Window", "RP Renamer"))
self.label.setText(_translate("Window", "Last Source Directory:"))
self.loadFilesButton.setText(_translate("Window", "&Load Files"))
self.label_2.setText(_translate("Window", "Files to Rename"))
self.label_3.setText(_translate("Window", "Renamed Files"))
self.label_4.setText(_translate("Window", "Filename Prefix:"))
self.prefixEdit.setPlaceholderText(
_translate("Window", "Rename your files to...")
)
self.extensionLabel.setText(_translate("Window", "*.jpg"))
self.renameFilesButton.setText(_translate("Window", "&Rename"))18.9 파일: source_code_final/rprename/views.py
이 모듈은 RP Renamer 기본 창을 제공합니다.
# -*- coding: utf-8 -*-
"""This module provides the RP Renamer main window."""
from collections import deque
from pathlib import Path
from PyQt5.QtCore import QThread
from PyQt5.QtWidgets import QFileDialog, QWidget
from .rename import Renamer
from .ui.window import Ui_Window
FILTERS = ";;".join(
(
"PNG Files (*.png)",
"JPEG Files (*.jpeg)",
"JPG Files (*.jpg)",
"GIF Files (*.gif)",
"Text Files (*.txt)",
"Python Files (*.py)",
)
)
class Window(QWidget, Ui_Window):
def __init__(self):
super().__init__()
self._files = deque()
self._filesCount = len(self._files)
self._setupUI()
self._connectSignalsSlots()
def _setupUI(self):
self.setupUi(self)
self._updateStateWhenNoFiles()
def _updateStateWhenNoFiles(self):
self._filesCount = len(self._files)
self.loadFilesButton.setEnabled(True)
self.loadFilesButton.setFocus(True)
self.renameFilesButton.setEnabled(False)
self.prefixEdit.clear()
self.prefixEdit.setEnabled(False)
def _connectSignalsSlots(self):
self.loadFilesButton.clicked.connect(self.loadFiles)
self.renameFilesButton.clicked.connect(self.renameFiles)
self.prefixEdit.textChanged.connect(self._updateStateWhenReady)
def _updateStateWhenReady(self):
if self.prefixEdit.text():
self.renameFilesButton.setEnabled(True)
else:
self.renameFilesButton.setEnabled(False)
def loadFiles(self):
self.dstFileList.clear()
if self.dirEdit.text():
initDir = self.dirEdit.text()
else:
initDir = str(Path.home())
files, filter = QFileDialog.getOpenFileNames(
self, "Choose Files to Rename", initDir, filter=FILTERS
)
if len(files) > 0:
fileExtension = filter[filter.index("*") : -1]
self.extensionLabel.setText(fileExtension)
srcDirName = str(Path(files[0]).parent)
self.dirEdit.setText(srcDirName)
for file in files:
self._files.append(Path(file))
self.srcFileList.addItem(file)
self._filesCount = len(self._files)
self._updateStateWhenFilesLoaded()
def _updateStateWhenFilesLoaded(self):
self.prefixEdit.setEnabled(True)
self.prefixEdit.setFocus(True)
def renameFiles(self):
self._runRenamerThread()
self._updateStateWhileRenaming()
def _updateStateWhileRenaming(self):
self.loadFilesButton.setEnabled(False)
self.renameFilesButton.setEnabled(False)
def _runRenamerThread(self):
prefix = self.prefixEdit.text()
self._thread = QThread()
self._renamer = Renamer(
files=tuple(self._files),
prefix=prefix,
)
self._renamer.moveToThread(self._thread)
# Rename
self._thread.started.connect(self._renamer.renameFiles)
# Update state
self._renamer.renamedFile.connect(self._updateStateWhenFileRenamed)
self._renamer.progressed.connect(self._updateProgressBar)
self._renamer.finished.connect(self._updateStateWhenNoFiles)
# Clean up
self._renamer.finished.connect(self._thread.quit)
self._renamer.finished.connect(self._renamer.deleteLater)
self._thread.finished.connect(self._thread.deleteLater)
# Run the thread
self._thread.start()
def _updateStateWhenFileRenamed(self, newFile):
self._files.popleft()
self.srcFileList.takeItem(0)
self.dstFileList.addItem(str(newFile))
def _updateProgressBar(self, fileNumber):
progressPercent = int(fileNumber / self._filesCount * 100)
self.progressBar.setValue(progressPercent)18.10 파일: source_code_final/rprenamer.py
이 모듈은 RP Renamer 진입점 스크립트를 제공합니다.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# rprenamer.py
"""This module provides the RP Renamer entry point script."""
from rprename.app import main
if __name__ == "__main__":
main()