개요
주로 사용된 기술과 스킬은
- 파일 이동,이름명 변경을 통해 파일의 기본적인 구조와 활용 이해
- 파일 클래스를 심화 응용
- 사용자 편의 및 프로젝트와 유사하게 기획 및 구현
내용
안녕하세요~!
지난 포스팅으로 연속적으로 파일을 다루는 자바 함수들을 이용해서 간단한 프로그램 2개를 만들어보았습니다!
[상위폴더로 하위폴더의 파일들을 이동시키는 프로그램] https://uno-kim.tistory.com/390
[파일]특정 폴더 하위 폴더의 파일들을 이동시키는 프로그램
안녕하세요! 그 동안 제가 취미(??) 생활로 이것저것 수집을 좋아해서 수집활동을 꾸준히 하고있는데 웹상에서 떠돌고있는 폴더들을 크롤링 또는 다운로드를 특정 폴더에 받게끔하면 폴더안에
uno-kim.tistory.com
[폴더안의 이름중 특정 구분자가 있다면 처리하는 프로그램] https://uno-kim.tistory.com/391
[파일]선택한 폴더 내의 파일들의 이름을 일괄 변경하는 프로그램
안녕하세요! 이번엔 특정 폴더 내부의 파일들의 이름을 일괄 변경하는 프로그램을 만들어 보겠습니다.!! 이전 포스팅으로는 특정폴더내의 폴더들의 내부 파일들을 모두 상위 폴더로 이동하는
uno-kim.tistory.com
이렇게 2개의 프로그램을 이제 하나의 프로그램으로 합쳐 최종적으로 자동화업무에 한발 다가설수있도록 작성하겠습니다!!

프로그램 기능 요약
크롤링 및 단순다운로드 등으로 자료파일들을 획득하고있습니다.
그 자료파일 또는 폴더들이 일괄적으로 저장되는 디렉토리가 있습니다.
그 디렉토리에 저장된 하위 폴더엔 동영상 및 이미지 파일등이 존재합니다.
이 파일들을 모두 상위 폴더로 이동시키고,
파일명들이 특정패턴(구분자 등)을 통해 저장되어져있다면
구분자로 나누어 파일명도 동시에 변경되는 프로그램입니다.
기존, 사람이 직접 폴더를 열고 상위 폴더로 옮기고, 파일이름을 @를 기준으로
@기준 왼쪽부분을 삭제하는 로직을
자바의 소스로 이제 자동화되도록 했습니다.
실행화면
전체소스
전체소스는 아래 접은글내부에 있습니다.
소스가 많이 깁니다. 따라서 접어서 작성했습니다.
package Java.File.Rename;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
public class FileMoveAndDeleteFolder {
private static HashMap<String, Function<String, String>> functionMap = new HashMap<>();
private static List<String> supportedFormats = Arrays.asList(".avi", ".mp4", ".mkv", ".mov", ".wmv", ".bmp");
public static void main(String[] args) {
JFrame frame = new JFrame("Move File");
JLabel label = new JLabel("Move File");
JButton selectButton = new JButton("폴더 선택");
JTextArea resultArea = new JTextArea(10, 15);
JButton renameButton = new JButton("변환하기!");
JTextArea convertedListTextArea = new JTextArea(10, 15);
convertedListTextArea.setLineWrap(true); // 줄 바꿈 설정
convertedListTextArea.setWrapStyleWord(true); // 단어 단위로 줄 바꿈
JScrollPane scrollPane = new JScrollPane(convertedListTextArea);
List<JComponent> componentList = Arrays.asList(label, selectButton, resultArea, renameButton,
convertedListTextArea);
setMainFrame(frame, componentList);
setMainLabel(label);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
selectButton.addActionListener(e -> {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
int option = fileChooser.showOpenDialog(frame);
if (option == JFileChooser.APPROVE_OPTION) {
File folder = fileChooser.getSelectedFile();
resultArea.setText(folder.getAbsolutePath());
renameButton.setEnabled(true);
}
});
renameButton.addActionListener(e -> {
String folderPath = resultArea.getText();
if (!folderPath.isEmpty()) {
File folder = new File(folderPath);
moveFile(folder, convertedListTextArea);
}
});
setFunctionMap();
}
private static void setMainLabel(JLabel label) {
label.setFont(new Font("Arial", Font.BOLD, 20));
label.setHorizontalAlignment(JLabel.CENTER);
}
private static void setMainFrame(JFrame frame, List<JComponent> componentList) {
frame.setPreferredSize(new Dimension(400, 500));
frame.getContentPane().add(createMainPanel(componentList));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null); // 화면 정중앙에 위치
frame.setVisible(true);
}
public static JPanel createMainPanel(List<JComponent> arr) {
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(4, 1, 10, 10));
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
arr.forEach(component -> panel.add(component));
return panel;
}
private static void moveFile(final File sourceDirectory, JTextArea convertedListTextArea) {
if (!checkDirectory(sourceDirectory)) {
convertedListTextArea.setText("선택한 경로는 폴더가 아닙니다.");
return;
}
File[] subDirectories = sourceDirectory.listFiles(File::isDirectory);
if (!checkFileExisting(subDirectories)) {
convertedListTextArea.setText("하위 디렉토리가 없습니다.");
return;
}
List<String> convertedFiles = new ArrayList<>();
moveFileAndSetSuccessFileNames(sourceDirectory, subDirectories, convertedFiles);
displayConvertedFiles(convertedFiles, convertedListTextArea);
confirmRenameFiles(sourceDirectory);
}
private static void moveFileAndSetSuccessFileNames(final File sourceDirectory, File[] subDirectories,
List<String> convertedFiles) {
for (File subDir : subDirectories) {
File[] videoFiles = subDir.listFiles((dir, name) -> {
String lowercaseName = name.toLowerCase();
return supportedFormats.stream().anyMatch(format -> lowercaseName.endsWith(format));
});
if (checkFileExisting(videoFiles)) {
for (File videoFile : videoFiles) {
String targetPath = sourceDirectory.getPath() + File.separator + videoFile.getName();
if (videoFile.renameTo(new File(targetPath))) {
convertedFiles.add("파일 성공 : " + videoFile.getName());
} else {
convertedFiles.add("파일 이동 실패 : " + videoFile.getName());
}
}
}
}
}
private static void confirmRenameFiles(File sourceDirectory) {
int confirmResult = JOptionPane.showConfirmDialog(null, "파일명도 일괄 변경하시겠습니까?", "확인", JOptionPane.YES_NO_OPTION);
if (confirmResult == JOptionPane.YES_OPTION) {
checkFilesAndRenameFiles(sourceDirectory);
} else if (confirmResult == JOptionPane.NO_OPTION) {
return;
}
}
private static void displayConvertedFiles(List<String> convertedFiles, JTextArea convertedListLabel) {
SwingUtilities.invokeLater(() -> {
convertedListLabel.append("변환된 파일 리스트:\n");
for (String filePath : convertedFiles) {
convertedListLabel.append(filePath + "\n");
convertedListLabel.setCaretPosition(convertedListLabel.getDocument().getLength());
}
});
}
private static void setFunctionMap() {
functionMap.put("@", filename -> filename.substring(filename.lastIndexOf("@") + 1));
functionMap.put("%", filename -> filename.substring(filename.indexOf("%") + 1, filename.lastIndexOf(".")));
}
private static boolean checkDirectory(File file) {
return (file != null && file.isDirectory());
}
private static boolean checkFileExisting(File[] files) {
return (files != null && files.length > 0);
}
private static void checkFilesAndRenameFiles(File folder) {
if (checkDirectory(folder)) {
File[] files = folder.listFiles();
if (files == null || files.length == 0)
return;
for (File file : files) {
renameFile(folder, file);
}
JOptionPane.showMessageDialog(null, "파일 이름 변경이 완료되었습니다.");
}
}
private static void renameFile(File toFolder, File file) {
if (file.isFile()) {
String originFileName = file.getName();
String newFilename = originFileName;
Set<String> separators = functionMap.keySet();
for (String separator : separators) {
if (newFilename.contains(separator)) {
newFilename = functionMap.get(separator).apply(newFilename);
}
}
rename(toFolder, file, newFilename);
}
}
private static void rename(File toFolder, File file, String newFilename) {
File newFile = new File(toFolder, newFilename);
try {
Files.move(file.toPath(), newFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
JOptionPane.showMessageDialog(null, "파일 이름 변경 중 오류가 발생했습니다.");
return;
}
}
}
간단한 설명
소스내부의 구체적인 소스는 위의 하이퍼링크를 통해 참고해주시면 감사하겠습니다.
우선은 첫번째로 프레임을 공통화하여 프로세스가 이어지도록 했습니다.

두번째로는 각 체크함수를 공통화 하여 체크하여 소스의 반복 및 가동석을 늘렸습니다.
세번째로는 각 기능과 컴포넌트별로 셋팅해주고 처리해주는 부분을 함수로 별도로 지정해주었습니다.
여기서 잠깐! 왜 프로그램이름이 FileMoveAndDeleteFolder 냐고 질문이 있을 수 있습니다.
처음 초기 설계는 파일을 전부 이동시키고 폴더를 삭제 시켜
[폴더이동]->[파일명 변경]->[폴더삭제] 이렇게 진행하는 것으로 계획하였으나,
폴더를 삭제하는 과정에서 실제 옮겨지지 않은 파일들이 존재하여 파일이 유실될까 작성하지 않았습니다.
나중에 이를 보완하는 방법으로 해당 방법을 모색해서 다시한번 포스팅을 작성하겠습니다.
이것으로 폴더 이동과 폴더 명 변경을 이용한 프로그램을 마치겠습니다.
긴글 읽어 주셔서 감사합니다!
무더운 여름날 모두 지혜롭게 이겨내고 가정에 화평이 깃들기를 기도하겠습니다.
댓글