Skip to content

Commit 6040ab0

Browse files
committed
优化文件解压缩功能
1 parent 22a3504 commit 6040ab0

6 files changed

Lines changed: 230 additions & 16 deletions

File tree

README_EN.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ Support plug-in development, the plug-in jar package can be automatically loaded
105105
52. SealBuilderTool: Stamp Generation Tool
106106
53. BullsAndCowsGame: A number guessing game
107107
54. FileUnicodeTransformationTool: File encoding conversion tool
108+
55. FileCompressTool: File decompression tool (currently supports ar, zip, tar, jar, cpio, 7z, gz, bzip2, xz, lzma, pack200, deflate, snappy-framed, lz4-block, lz4-framed, ZSTD, etc.)
108109

109110
##### The transfer tools currently support the following features:
110111
###### Receiver:

src/main/java/com/xwintop/xJavaFxTool/controller/littleTools/FileCompressToolController.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.xwintop.xJavaFxTool.services.littleTools.FileCompressToolService;
44
import com.xwintop.xJavaFxTool.view.littleTools.FileCompressToolView;
55
import com.xwintop.xcore.util.javafx.FileChooserUtil;
6+
import com.xwintop.xcore.util.javafx.TooltipUtil;
67
import javafx.event.ActionEvent;
78
import javafx.fxml.FXML;
89
import javafx.stage.FileChooser;
@@ -47,7 +48,7 @@ private void initView() {
4748
}
4849

4950
private void initEvent() {
50-
FileChooserUtil.setOnDrag(selectFileTextField, FileChooserUtil.FileType.FOLDER);
51+
FileChooserUtil.setOnDrag(selectFileTextField, FileChooserUtil.FileType.FILE);
5152
FileChooserUtil.setOnDrag(saveFilePathTextField, FileChooserUtil.FileType.FOLDER);
5253
}
5354

@@ -92,7 +93,12 @@ private void saveFilePathAction(ActionEvent event) {
9293

9394
@FXML
9495
private void compressAction(ActionEvent event) {
95-
fileCompressToolService.compressAction();
96+
try {
97+
fileCompressToolService.compressAction();
98+
} catch (Exception e) {
99+
log.error("操作失败:", e);
100+
TooltipUtil.showToast("操作失败!" + e.getMessage());
101+
}
96102
}
97103

98104
}

src/main/java/com/xwintop/xJavaFxTool/services/littleTools/FileCompressToolService.java

Lines changed: 173 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,32 @@
44
import lombok.Getter;
55
import lombok.Setter;
66
import lombok.extern.slf4j.Slf4j;
7+
import org.apache.commons.compress.archivers.ArchiveEntry;
8+
import org.apache.commons.compress.archivers.ArchiveInputStream;
9+
import org.apache.commons.compress.archivers.ArchiveOutputStream;
10+
import org.apache.commons.compress.archivers.ArchiveStreamFactory;
11+
import org.apache.commons.compress.archivers.ar.ArArchiveOutputStream;
12+
import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry;
13+
import org.apache.commons.compress.archivers.sevenz.SevenZFile;
14+
import org.apache.commons.compress.archivers.sevenz.SevenZOutputFile;
15+
import org.apache.commons.compress.compressors.CompressorInputStream;
16+
import org.apache.commons.compress.compressors.CompressorOutputStream;
17+
import org.apache.commons.compress.compressors.CompressorStreamFactory;
18+
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
19+
import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
20+
import org.apache.commons.compress.compressors.gzip.GzipParameters;
21+
import org.apache.commons.compress.utils.IOUtils;
22+
import org.apache.commons.compress.utils.SeekableInMemoryByteChannel;
23+
import org.apache.commons.io.FileUtils;
24+
import org.apache.commons.io.FilenameUtils;
25+
import org.apache.commons.lang3.StringUtils;
26+
27+
import java.io.ByteArrayOutputStream;
28+
import java.io.File;
29+
import java.io.FileInputStream;
30+
import java.util.ArrayList;
31+
import java.util.Arrays;
32+
import java.util.List;
733

834
/**
935
* @ClassName: FileCompressToolService
@@ -22,7 +48,153 @@ public FileCompressToolService(FileCompressToolController fileCompressToolContro
2248
this.fileCompressToolController = fileCompressToolController;
2349
}
2450

25-
public void compressAction() {
51+
public void compressAction() throws Exception {
52+
String zipType = fileCompressToolController.getFileTypeChoiceBox().getValue();
53+
String filePath = fileCompressToolController.getSelectFileTextField().getText();
54+
String saveFilePath = fileCompressToolController.getSaveFilePathTextField().getText();
55+
if (fileCompressToolController.getCompressCheckBox().isSelected()) {
56+
byte[] zippedData = null;
57+
if (new ArchiveStreamFactory().getOutputStreamArchiveNames().contains(zipType.toLowerCase())) {
58+
zippedData = this.zip(filePath, zipType);
59+
} else if (CompressorStreamFactory.getSingleton().getOutputStreamCompressorNames().contains(zipType.toLowerCase())) {
60+
zippedData = this.gzip(filePath, zipType);
61+
} else {
62+
log.warn("未支持该压缩格式:" + zipType + " fileName:" + filePath);
63+
return;
64+
}
65+
String[] filePaths = filePath.split("\\|");
66+
List<File> fileList = new ArrayList<>();
67+
for (String path : filePaths) {
68+
File file = new File(path);
69+
if (file.isDirectory()) {
70+
fileList.addAll(Arrays.asList(file.listFiles()));
71+
} else {
72+
fileList.add(file);
73+
}
74+
}
75+
if (StringUtils.isEmpty(saveFilePath)) {
76+
saveFilePath = FilenameUtils.getFullPath(fileList.get(0).getPath());
77+
}
78+
FileUtils.writeByteArrayToFile(new File(saveFilePath, fileList.get(0).getName() + "." + zipType), zippedData);
79+
} else {
80+
if ("AUTO".equalsIgnoreCase(zipType)) {
81+
try {
82+
zipType = ArchiveStreamFactory.detect(new FileInputStream(new File(filePath)));
83+
} catch (Exception e) {
84+
try {
85+
zipType = CompressorStreamFactory.detect(new FileInputStream(new File(filePath)));
86+
} catch (Exception e1) {
87+
log.warn("未识别出压缩类型:" + " fileName:" + filePath);
88+
}
89+
}
90+
}
91+
if (new ArchiveStreamFactory().getInputStreamArchiveNames().contains(zipType.toLowerCase())) {
92+
this.unzip(filePath, zipType);
93+
} else if (CompressorStreamFactory.getSingleton().getInputStreamCompressorNames().contains(zipType.toLowerCase())) {
94+
this.ungzip(filePath, zipType);
95+
} else {
96+
log.warn("未支持该压缩格式:" + zipType + " fileName:" + filePath);
97+
}
98+
}
99+
}
100+
101+
private byte[] zip(String filePath, String zipType) throws Exception {
102+
String[] filePaths = filePath.split("\\|");
103+
List<File> fileList = new ArrayList<>();
104+
for (String path : filePaths) {
105+
File file = new File(path);
106+
if (file.isDirectory()) {
107+
fileList.addAll(Arrays.asList(file.listFiles()));
108+
} else {
109+
fileList.add(file);
110+
}
111+
}
112+
if (ArchiveStreamFactory.SEVEN_Z.equalsIgnoreCase(zipType)) {
113+
SeekableInMemoryByteChannel seekableByteChannel = new SeekableInMemoryByteChannel();
114+
SevenZOutputFile sevenZOutput = new SevenZOutputFile(seekableByteChannel);
115+
for (File file : fileList) {
116+
SevenZArchiveEntry entry = sevenZOutput.createArchiveEntry(file, file.getName());
117+
sevenZOutput.putArchiveEntry(entry);
118+
sevenZOutput.write(FileUtils.readFileToByteArray(file));
119+
sevenZOutput.closeArchiveEntry();
120+
}
121+
sevenZOutput.close();
122+
return seekableByteChannel.array();
123+
}
124+
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
125+
ArchiveOutputStream archiveOutputStream = new ArchiveStreamFactory().createArchiveOutputStream(zipType, outputStream);
126+
for (File file : fileList) {
127+
if (archiveOutputStream instanceof ArArchiveOutputStream) {
128+
((ArArchiveOutputStream) archiveOutputStream).setLongFileMode(ArArchiveOutputStream.LONGFILE_BSD);
129+
}
130+
ArchiveEntry entry = archiveOutputStream.createArchiveEntry(file, file.getName());
131+
archiveOutputStream.putArchiveEntry(entry);
132+
archiveOutputStream.write(FileUtils.readFileToByteArray(file));
133+
archiveOutputStream.closeArchiveEntry();
134+
}
135+
archiveOutputStream.close();
136+
return outputStream.toByteArray();
137+
}
138+
139+
private byte[] gzip(String filePath, String zipType) throws Exception {
140+
File file = new File(filePath);
141+
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
142+
CompressorOutputStream compressorOutputStream;
143+
if (CompressorStreamFactory.GZIP.equalsIgnoreCase(zipType)) {
144+
GzipParameters gzipParameters = new GzipParameters();
145+
gzipParameters.setFilename(file.getName());
146+
compressorOutputStream = new GzipCompressorOutputStream(outputStream, gzipParameters);
147+
} else {
148+
compressorOutputStream = CompressorStreamFactory.getSingleton().createCompressorOutputStream(zipType, outputStream);
149+
}
150+
compressorOutputStream.write(FileUtils.readFileToByteArray(file));
151+
compressorOutputStream.close();
152+
return outputStream.toByteArray();
153+
}
154+
155+
private void unzip(String filePath, String zipType) throws Exception {
156+
String saveFilePath = fileCompressToolController.getSaveFilePathTextField().getText();
157+
if (StringUtils.isEmpty(saveFilePath)) {
158+
saveFilePath = FilenameUtils.getFullPath(filePath);
159+
}
160+
if (ArchiveStreamFactory.SEVEN_Z.equalsIgnoreCase(zipType)) {
161+
SevenZFile sevenZFile = new SevenZFile(new File(filePath));
162+
SevenZArchiveEntry entry = null;
163+
while ((entry = sevenZFile.getNextEntry()) != null) {
164+
byte[] bytes = new byte[(int) entry.getSize()];
165+
sevenZFile.read(bytes); // read current entry's data
166+
FileUtils.writeByteArrayToFile(new File(saveFilePath, entry.getName()), bytes);
167+
}
168+
sevenZFile.close();
169+
}
170+
ArchiveInputStream archiveInputStream = new ArchiveStreamFactory().createArchiveInputStream(zipType, new FileInputStream(filePath));
171+
ArchiveEntry entry = null;
172+
while ((entry = archiveInputStream.getNextEntry()) != null) {
173+
if (!entry.isDirectory()) {
174+
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
175+
IOUtils.copy(archiveInputStream, outputStream);
176+
FileUtils.writeByteArrayToFile(new File(saveFilePath, entry.getName()), outputStream.toByteArray());
177+
}
178+
}
179+
archiveInputStream.close();
180+
}
26181

182+
private void ungzip(String filePath, String zipType) throws Exception {
183+
String saveFilePath = fileCompressToolController.getSaveFilePathTextField().getText();
184+
CompressorInputStream compressorInputStream = CompressorStreamFactory.getSingleton().createCompressorInputStream(zipType, new FileInputStream(filePath));
185+
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
186+
IOUtils.copy(compressorInputStream, outputStream);
187+
compressorInputStream.close();
188+
String entryFileName = null;
189+
if (compressorInputStream instanceof GzipCompressorInputStream) {
190+
entryFileName = ((GzipCompressorInputStream) compressorInputStream).getMetaData().getFilename();
191+
}
192+
if (StringUtils.isEmpty(entryFileName)) {
193+
entryFileName = FilenameUtils.getBaseName(filePath);
194+
}
195+
if (StringUtils.isEmpty(saveFilePath)) {
196+
saveFilePath = FilenameUtils.getFullPath(filePath);
197+
}
198+
FileUtils.writeByteArrayToFile(new File(saveFilePath, entryFileName), outputStream.toByteArray());
27199
}
28200
}

src/main/java/com/xwintop/xJavaFxTool/view/littleTools/FileCompressToolView.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,6 @@ public abstract class FileCompressToolView implements Initializable {
3434
@FXML
3535
protected Button saveFilePathButton;
3636
@FXML
37-
protected ChoiceBox fileTypeChoiceBox;
37+
protected ChoiceBox<String> fileTypeChoiceBox;
3838

3939
}
Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,59 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22

3+
<?import javafx.geometry.Insets?>
34
<?import javafx.scene.control.Button?>
45
<?import javafx.scene.control.CheckBox?>
56
<?import javafx.scene.control.ChoiceBox?>
67
<?import javafx.scene.control.Label?>
78
<?import javafx.scene.control.TextField?>
89
<?import javafx.scene.layout.AnchorPane?>
10+
<?import javafx.scene.layout.HBox?>
11+
<?import javafx.scene.layout.VBox?>
912

1013
<AnchorPane prefHeight="400.0" prefWidth="702.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.xwintop.xJavaFxTool.controller.littleTools.FileCompressToolController">
1114
<children>
12-
<Label layoutX="31.0" layoutY="24.0" text="文件选择:" />
13-
<TextField fx:id="selectFileTextField" layoutX="99.0" layoutY="20.0" promptText="可选择目录或多个文件" />
14-
<Button fx:id="selectFileButton" layoutX="274.0" layoutY="20.0" mnemonicParsing="false" onAction="#selectFileAction" text="选择文件" />
15-
<Button fx:id="selectFolderButton" layoutX="351.0" layoutY="20.0" mnemonicParsing="false" onAction="#selectFolderAction" text="选择文件夹" />
16-
<Label layoutX="140.0" layoutY="82.0" text="文件压缩类型:" />
17-
<CheckBox fx:id="compressCheckBox" layoutX="39.0" layoutY="82.0" mnemonicParsing="false" selected="true" text="压缩" />
18-
<Button fx:id="compressButton" layoutX="331.0" layoutY="229.0" mnemonicParsing="false" onAction="#compressAction" text="开始" />
19-
<Label layoutX="29.0" layoutY="159.0" text="输出文件夹:" />
20-
<TextField fx:id="saveFilePathTextField" layoutX="101.0" layoutY="155.0" promptText="留空为原文件同目录" />
21-
<Button fx:id="saveFilePathButton" layoutX="266.0" layoutY="155.0" mnemonicParsing="false" onAction="#saveFilePathAction" text="选择" />
22-
<ChoiceBox fx:id="fileTypeChoiceBox" layoutX="236.0" layoutY="78.0" />
15+
<VBox layoutY="20.0" spacing="30.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
16+
<children>
17+
<HBox alignment="CENTER" spacing="10.0">
18+
<children>
19+
<Label text="文件选择:" />
20+
<TextField fx:id="selectFileTextField" promptText="可选择目录或多个文件" HBox.hgrow="ALWAYS" />
21+
<Button fx:id="selectFileButton" mnemonicParsing="false" onAction="#selectFileAction" text="选择文件" />
22+
<Button fx:id="selectFolderButton" mnemonicParsing="false" onAction="#selectFolderAction" text="选择文件夹" />
23+
</children>
24+
<padding>
25+
<Insets left="10.0" right="10.0" />
26+
</padding>
27+
</HBox>
28+
<HBox alignment="CENTER" spacing="10.0">
29+
<children>
30+
<CheckBox fx:id="compressCheckBox" mnemonicParsing="false" selected="true" text="压缩" />
31+
<Label text="文件压缩类型:" />
32+
<ChoiceBox fx:id="fileTypeChoiceBox" />
33+
</children>
34+
<padding>
35+
<Insets left="10.0" right="10.0" />
36+
</padding>
37+
</HBox>
38+
<HBox alignment="CENTER" spacing="10.0">
39+
<children>
40+
<Label text="输出文件夹:" />
41+
<TextField fx:id="saveFilePathTextField" promptText="留空为原文件同目录" HBox.hgrow="ALWAYS" />
42+
<Button fx:id="saveFilePathButton" mnemonicParsing="false" onAction="#saveFilePathAction" text="选择" />
43+
</children>
44+
<padding>
45+
<Insets left="10.0" right="10.0" />
46+
</padding>
47+
</HBox>
48+
<HBox alignment="CENTER">
49+
<children>
50+
<Button fx:id="compressButton" mnemonicParsing="false" onAction="#compressAction" text="开始" />
51+
</children>
52+
</HBox>
53+
</children>
54+
<padding>
55+
<Insets top="30.0" />
56+
</padding>
57+
</VBox>
2358
</children>
2459
</AnchorPane>

src/main/resources/config/toolFxmlLoaderConfiguration.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@
314314
<url>/com/xwintop/xJavaFxTool/fxmlView/littleTools/FileCompressTool.fxml</url>
315315
<title>FileCompressTool</title>
316316
<menuParentId>littleTools</menuParentId>
317-
<isDefaultShow>true</isDefaultShow>
317+
<isDefaultShow></isDefaultShow>
318318
</ToolFxmlLoaderConfiguration>
319319

320320
<ToolFxmlLoaderConfiguration url="/web/littleTools/cron/index.htm"

0 commit comments

Comments
 (0)