added support for zip

This commit is contained in:
rdavidek 2026-01-14 20:35:24 +01:00
parent 5a7312eb8e
commit dcc9a6a418
2 changed files with 202 additions and 0 deletions

View File

@ -8,6 +8,7 @@ import java.nio.file.attribute.BasicFileAttributes;
import java.util.List; import java.util.List;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.zip.*;
/** /**
* Service for file operations - copy, move, delete, etc. * Service for file operations - copy, move, delete, etc.
@ -237,6 +238,100 @@ public class FileOperations {
} }
} }
/**
* Zip files/directories into a target zip file
*/
public static void zip(List<FileItem> items, File targetZipFile, ProgressCallback callback) throws IOException {
try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(targetZipFile))) {
int current = 0;
int total = items.size();
for (FileItem item : items) {
current++;
File source = item.getFile();
if (callback != null) {
callback.onProgress(current, total, source.getName());
}
addToZip(source, source.getName(), zos);
}
}
}
private static void addToZip(File fileToZip, String fileName, ZipOutputStream zos) throws IOException {
if (fileToZip.isHidden()) {
return;
}
if (fileToZip.isDirectory()) {
if (fileName.endsWith("/")) {
zos.putNextEntry(new ZipEntry(fileName));
zos.closeEntry();
} else {
zos.putNextEntry(new ZipEntry(fileName + "/"));
zos.closeEntry();
}
File[] children = fileToZip.listFiles();
if (children != null) {
for (File childFile : children) {
addToZip(childFile, fileName + "/" + childFile.getName(), zos);
}
}
return;
}
try (FileInputStream fis = new FileInputStream(fileToZip)) {
ZipEntry zipEntry = new ZipEntry(fileName);
zos.putNextEntry(zipEntry);
byte[] bytes = new byte[1024];
int length;
while ((length = fis.read(bytes)) >= 0) {
zos.write(bytes, 0, length);
}
zos.closeEntry();
}
}
/**
* Unzip a zip file into a target directory
*/
public static void unzip(File zipFile, File targetDirectory, ProgressCallback callback) throws IOException {
if (!targetDirectory.exists()) {
Files.createDirectories(targetDirectory.toPath());
}
try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile))) {
ZipEntry entry;
// First pass or estimated count could be done, but keep it simple for now
while ((entry = zis.getNextEntry()) != null) {
File newFile = new File(targetDirectory, entry.getName());
if (callback != null) {
callback.onProgress(0, 0, entry.getName());
}
if (entry.isDirectory()) {
if (!newFile.isDirectory() && !newFile.mkdirs()) {
throw new IOException("Failed to create directory " + newFile);
}
} else {
// create parent directories if they don't exist
File parent = newFile.getParentFile();
if (!parent.isDirectory() && !parent.mkdirs()) {
throw new IOException("Failed to create directory " + parent);
}
// write file content
try (FileOutputStream fos = new FileOutputStream(newFile)) {
byte[] buffer = new byte[1024];
int len;
while ((len = zis.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
}
}
zis.closeEntry();
}
}
}
// legacy matchesPattern removed filename wildcard handling is done via a precompiled Pattern // legacy matchesPattern removed filename wildcard handling is done via a precompiled Pattern
/** /**

View File

@ -423,6 +423,16 @@ public class MainWindow extends JFrame {
KeyStroke.getKeyStroke(KeyEvent.VK_F5, 0), KeyStroke.getKeyStroke(KeyEvent.VK_F5, 0),
JComponent.WHEN_IN_FOCUSED_WINDOW); JComponent.WHEN_IN_FOCUSED_WINDOW);
// Alt+F5 - Zip
rootPane.registerKeyboardAction(e -> zipFiles(),
KeyStroke.getKeyStroke(KeyEvent.VK_F5, InputEvent.ALT_DOWN_MASK),
JComponent.WHEN_IN_FOCUSED_WINDOW);
// Alt+F9 - Unzip
rootPane.registerKeyboardAction(e -> unzipFiles(),
KeyStroke.getKeyStroke(KeyEvent.VK_F9, InputEvent.ALT_DOWN_MASK),
JComponent.WHEN_IN_FOCUSED_WINDOW);
// F6 - Move // F6 - Move
rootPane.registerKeyboardAction(e -> moveFiles(), rootPane.registerKeyboardAction(e -> moveFiles(),
KeyStroke.getKeyStroke(KeyEvent.VK_F6, 0), KeyStroke.getKeyStroke(KeyEvent.VK_F6, 0),
@ -701,6 +711,101 @@ public class MainWindow extends JFrame {
} }
} }
/**
* Zip selected files
*/
private void zipFiles() {
List<FileItem> selectedItems = activePanel.getSelectedItems();
if (selectedItems.isEmpty()) {
JOptionPane.showMessageDialog(this,
"No files selected",
"Zip",
JOptionPane.INFORMATION_MESSAGE);
return;
}
String defaultName;
if (selectedItems.size() == 1) {
defaultName = selectedItems.get(0).getName();
} else {
defaultName = activePanel.getCurrentDirectory().getName();
if (defaultName == null || defaultName.isEmpty() || defaultName.equals("/") || defaultName.endsWith(":")) {
defaultName = "archive";
}
}
if (defaultName.contains(".")) {
int lastDot = defaultName.lastIndexOf('.');
if (lastDot > 0) {
defaultName = defaultName.substring(0, lastDot);
}
}
defaultName += ".zip";
String zipName = JOptionPane.showInputDialog(this, "Enter zip filename:", defaultName);
if (zipName == null || zipName.trim().isEmpty()) {
return;
}
if (!zipName.toLowerCase().endsWith(".zip")) {
zipName += ".zip";
}
FilePanel targetPanel = (activePanel == leftPanel) ? rightPanel : leftPanel;
File targetDir = targetPanel.getCurrentDirectory();
File targetZip = new File(targetDir, zipName);
if (targetZip.exists()) {
int confirm = JOptionPane.showConfirmDialog(this,
"File already exists. Overwrite?", "Zip", JOptionPane.YES_NO_OPTION);
if (confirm != JOptionPane.YES_OPTION) {
return;
}
}
final File finalTargetZip = targetZip;
performFileOperation(() -> {
FileOperations.zip(selectedItems, finalTargetZip, null);
}, "Zabaleno do " + zipName, targetPanel);
}
/**
* Unzip selected zip file
*/
private void unzipFiles() {
List<FileItem> selectedItems = activePanel.getSelectedItems();
if (selectedItems.isEmpty()) {
JOptionPane.showMessageDialog(this,
"No files selected",
"Unzip",
JOptionPane.INFORMATION_MESSAGE);
return;
}
File zipFile = selectedItems.get(0).getFile();
if (!zipFile.getName().toLowerCase().endsWith(".zip")) {
JOptionPane.showMessageDialog(this,
"Selected file is not a ZIP archive",
"Unzip",
JOptionPane.ERROR_MESSAGE);
return;
}
FilePanel targetPanel = (activePanel == leftPanel) ? rightPanel : leftPanel;
File targetDir = targetPanel.getCurrentDirectory();
int result = JOptionPane.showConfirmDialog(this,
String.format("Unzip %s to:\n%s", zipFile.getName(), targetDir.getAbsolutePath()),
"Unzip",
JOptionPane.OK_CANCEL_OPTION);
if (result == JOptionPane.OK_OPTION) {
performFileOperation(() -> {
FileOperations.unzip(zipFile, targetDir, null);
}, "Rozbaleno do " + targetDir.getName(), targetPanel);
}
}
/** /**
* Rename selected file * Rename selected file
*/ */
@ -914,6 +1019,8 @@ public class MainWindow extends JFrame {
"Java 11\n\n" + "Java 11\n\n" +
"Keyboard shortcuts:\n" + "Keyboard shortcuts:\n" +
"F5 - Copy\n" + "F5 - Copy\n" +
"Alt+F5 - Zip\n" +
"Alt+F9 - Unzip\n" +
"F6 - Move\n" + "F6 - Move\n" +
"F7 - New directory\n" + "F7 - New directory\n" +
"F8 - Delete\n" + "F8 - Delete\n" +