コンソールではなくGUIで対話式のインターフェースを提供するために、JavaのSwingを使用します。以下に、Swingを用いて対話式のファイル比較ツールを実装したコードを示します。
Swingを用いた対話式ファイル比較ツール
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.nio.file.*;
import java.util.*;
import java.util.concurrent.*;
public class FileComparator extends JFrame {
private static final int THREAD_POOL_SIZE = 4; // Intel i5の4コアに合わせて設定
private static final int BUFFER_SIZE = 8192;
private JTextField sourceFolderPathField;
private JTextField targetFolderPathField;
private JTextArea outputArea;
private JButton compareButton;
public FileComparator() {
setTitle("ファイル比較ツール");
setSize(600, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
JPanel inputPanel = new JPanel();
inputPanel.setLayout(new GridLayout(3, 2));
inputPanel.add(new JLabel("ソースフォルダのパス:"));
sourceFolderPathField = new JTextField();
inputPanel.add(sourceFolderPathField);
inputPanel.add(new JLabel("ターゲットフォルダのパス:"));
targetFolderPathField = new JTextField();
inputPanel.add(targetFolderPathField);
compareButton = new JButton("比較開始");
inputPanel.add(compareButton);
add(inputPanel, BorderLayout.NORTH);
outputArea = new JTextArea();
outputArea.setEditable(false);
JScrollPane scrollPane = new JScrollPane(outputArea);
add(scrollPane, BorderLayout.CENTER);
compareButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String sourceFolderPath = sourceFolderPathField.getText();
String targetFolderPath = targetFolderPathField.getText();
if (!isValidFolder(sourceFolderPath) || !isValidFolder(targetFolderPath)) {
outputArea.append("提供されたフォルダパスが無効です。\n");
return;
}
outputArea.append("比較を開始します...\n");
long startTime = System.currentTimeMillis();
compareFolders(sourceFolderPath, targetFolderPath);
long endTime = System.currentTimeMillis();
outputArea.append("処理時間: " + (endTime - startTime) + " ミリ秒\n");
}
});
}
private boolean isValidFolder(String folderPath) {
File folder = new File(folderPath);
return folder.isDirectory();
}
private void compareFolders(String sourceFolderPath, String targetFolderPath) {
File sourceFolder = new File(sourceFolderPath);
File targetFolder = new File(targetFolderPath);
File[] sourceFiles = sourceFolder.listFiles();
File[] targetFiles = targetFolder.listFiles();
Map<String, File> sourceFileMap = new HashMap<>();
Map<String, File> targetFileMap = new HashMap<>();
if (sourceFiles != null) {
for (File file : sourceFiles) {
sourceFileMap.put(file.getName(), file);
}
}
if (targetFiles != null) {
for (File file : targetFiles) {
targetFileMap.put(file.getName(), file);
}
}
Set<String> allFileNames = new HashSet<>();
allFileNames.addAll(sourceFileMap.keySet());
allFileNames.addAll(targetFileMap.keySet());
ExecutorService executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
List<Future<?>> futures = new ArrayList<>();
for (String fileName : allFileNames) {
Future<?> future = executorService.submit(() -> {
File sourceFile = sourceFileMap.get(fileName);
File targetFile = targetFileMap.get(fileName);
try {
if (sourceFile == null) {
// 追加データ
writeToFile(targetFile, "updatedData.txt", "追加データ: " + fileName);
outputArea.append("追加データ: " + fileName + "\n");
} else if (targetFile == null) {
// 削除データ
writeToFile(sourceFile, "deletedData.txt", "削除データ: " + fileName);
outputArea.append("削除データ: " + fileName + "\n");
} else {
// 差分比較
compareFiles(sourceFile, targetFile, "updatedData.txt");
}
} catch (IOException e) {
outputArea.append("ファイル処理中のエラー: " + fileName + "\n");
e.printStackTrace();
}
});
futures.add(future);
}
for (Future<?> future : futures) {
try {
future.get();
} catch (InterruptedException | ExecutionException e) {
outputArea.append("並行実行中のエラー\n");
e.printStackTrace();
}
}
executorService.shutdown();
}
private void compareFiles(File sourceFile, File targetFile, String outputFileName) throws IOException {
try (BufferedReader sourceReader = new BufferedReader(new FileReader(sourceFile), BUFFER_SIZE);
BufferedReader targetReader = new BufferedReader(new FileReader(targetFile), BUFFER_SIZE)) {
String sourceLine;
String targetLine;
boolean differencesFound = false;
while ((sourceLine = sourceReader.readLine()) != null && (targetLine = targetReader.readLine()) != null) {
if (!sourceLine.equals(targetLine)) {
writeToFile(sourceFile, outputFileName, "更新あり: " + sourceFile.getName());
outputArea.append("更新あり: " + sourceFile.getName() + "\n");
differencesFound = true;
break;
}
}
if (!differencesFound && (sourceReader.readLine() != null || targetReader.readLine() != null)) {
writeToFile(sourceFile, outputFileName, "更新あり: " + sourceFile.getName());
outputArea.append("更新あり: " + sourceFile.getName() + "\n");
}
}
}
private void writeToFile(File file, String outputFileName, String header) throws IOException {
synchronized (FileComparator.class) {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(outputFileName, true), BUFFER_SIZE);
BufferedReader reader = new BufferedReader(new FileReader(file), BUFFER_SIZE)) {
writer.write(header);
writer.newLine();
String line;
while ((line = reader.readLine()) != null) {
writer.write(line);
writer.newLine();
}
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
FileComparator fileComparator = new FileComparator();
fileComparator.setVisible(true);
});
}
}
説明
-
GUIの構築:
-
JFrame
を拡張して、ファイル比較ツールのウィンドウを作成します。 - テキストフィールド(
JTextField
)を使用して、ユーザーがソースフォルダとターゲットフォルダのパスを入力できるようにします。 - 結果を表示するためのテキストエリア(
JTextArea
)を配置し、スクロール可能にします。
-
-
イベントハンドリング:
- 比較ボタン(
JButton
)にアクションリスナーを追加し、ボタンがクリックされたときにファイル比較処理を開始します。 - ユーザーが入力したフォルダパスの有効性をチェックし、無効な場合はエラーメッセージを表示します。
- 比較ボタン(
-
ファイル比較処理:
- 前述のコンソール版と同様に、フォルダ内のファイルをマップに格納し、並行処理で比較を行います。
- 比較結果は、テキストエリアにリアルタイムで表示されます。
このGUI版ツールにより、ユーザーは対話的にフォルダパスを入力し、ファイル比較の結果を直感的に確認することができます。