GZip是常用的無損壓縮算法實現,在Linux中較為常見,像我們在Linux安裝軟件時,基本都是.tar.gz格式。.tar.gz格式文件需要先對目錄內文件進行tar壓縮,然后使用GZip進行壓縮。
本文針對基于磁盤的壓縮和解壓進行演示,演示只針對一層目錄結構進行,多層目錄只需遞歸操作進行即可。
Maven依賴
org.apache.commons: commons-compress: 1.19: 此依賴封裝了很多壓縮算法相關的工具類,提供的API還是相對比較底層,我們今天在它的基礎上做進一步封裝。
1
2
3
4
5
6
7
8
9
10
|
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-compress</artifactId> <version> 1.19 </version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version> 1.2 . 17 </version> </dependency> |
工具類
其實,在通常情況下,我們都是在磁盤上進行壓縮和解壓操作的,這樣雖然增加了操作的復雜度,但是卻無形中避免了一些問題。
工具類針對.tar.gz格式提供了compressByTar、decompressByTar、compressByGZip、decompressByGZip四個方法,用于處理.tar.gz格式壓縮文件,代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
|
package com.arhorchin.securitit.compress.gzip; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream; import org.apache.commons.compress.utils.IOUtils; import org.apache.log4j.Logger; /** * @author Securitit. * @note 基于磁盤以GZIP算法進行壓縮和解壓工具類. */ public class GZipDiskUtil { /** * logger. */ private static Logger logger = Logger.getLogger(GZipDiskUtil. class ); /** * UTF-8字符集. */ public static String CHARSET_UTF8 = "UTF-8" ; /** * 使用TAR算法進行壓縮. * @param sourceFolderPath 待進行壓縮的文件夾路徑. * @param targetTarFilePath 壓縮后的TAR文件存儲目錄. * @return 壓縮是否成功. * @throws Exception 壓縮過程中可能發生的異常. */ public static boolean compressByTar(String sourceFolderPath, String targetTarFilePath) throws Exception { // 變量定義. File sourceFolderFile = null ; FileOutputStream targetTarFos = null ; TarArchiveOutputStream targetTartTaos = null ; TarArchiveEntry targetTarTae = null ; try { // 壓縮變量初始化. sourceFolderFile = new File(sourceFolderPath); targetTarFos = new FileOutputStream( new File(targetTarFilePath)); targetTartTaos = new TarArchiveOutputStream(targetTarFos); // 將文件添加到ZIP條目中. for (File file : sourceFolderFile.listFiles()) { try (FileInputStream fis = new FileInputStream(file); BufferedInputStream bis = new BufferedInputStream(fis);) { targetTarTae = new TarArchiveEntry(file); targetTarTae.setName(file.getName()); targetTartTaos.putArchiveEntry(targetTarTae); targetTartTaos.write(IOUtils.toByteArray(bis)); targetTartTaos.closeArchiveEntry(); } } } catch (Exception ex) { logger.info( "GZipDiskUtil.compressByTar." , ex); return false ; } finally { if (targetTartTaos != null ) targetTartTaos.close(); if (targetTarFos != null ) targetTarFos.close(); } return true ; } /** * 使用TAR算法進行解壓. * @param sourceTarPath 待解壓文件路徑. * @param targetFolderPath 解壓后文件夾目錄. * @return 解壓是否成功. * @throws Exception 解壓過程中可能發生的異常. */ public static boolean decompressByTar(String sourceTarPath, String targetFolderPath) throws Exception { // 變量定義. FileInputStream sourceTarFis = null ; TarArchiveInputStream sourceTarTais = null ; TarArchiveEntry sourceTarTae = null ; File singleEntryFile = null ; try { // 解壓定義初始化. sourceTarFis = new FileInputStream( new File(sourceTarPath)); sourceTarTais = new TarArchiveInputStream(sourceTarFis); // 條目解壓縮至指定文件夾目錄下. while ((sourceTarTae = sourceTarTais.getNextTarEntry()) != null ) { singleEntryFile = new File(targetFolderPath + File.separator + sourceTarTae.getName()); try (FileOutputStream fos = new FileOutputStream(singleEntryFile); BufferedOutputStream bos = new BufferedOutputStream(fos);) { bos.write(IOUtils.toByteArray(sourceTarTais)); } } } catch (Exception ex) { logger.info( "GZipDiskUtil.decompressByTar." , ex); return false ; } finally { if (sourceTarTais != null ) sourceTarTais.close(); if (sourceTarFis != null ) sourceTarFis.close(); } return true ; } /** * 使用GZIP算法進行壓縮. * @param sourceFilePath 待進行壓縮的文件路徑. * @param targetGZipFilePath 壓縮后的GZIP文件存儲目錄. * @return 壓縮是否成功. * @throws Exception 壓縮過程中可能發生的異常. */ public static boolean compressByGZip(String sourceFilePath, String targetGZipFilePath) throws IOException { // 變量定義. FileInputStream sourceFileFis = null ; BufferedInputStream sourceFileBis = null ; FileOutputStream targetGZipFileFos = null ; BufferedOutputStream targetGZipFileBos = null ; GzipCompressorOutputStream targetGZipFileGcos = null ; try { // 壓縮變量初始化. sourceFileFis = new FileInputStream( new File(sourceFilePath)); sourceFileBis = new BufferedInputStream(sourceFileFis); targetGZipFileFos = new FileOutputStream(targetGZipFilePath); targetGZipFileBos = new BufferedOutputStream(targetGZipFileFos); targetGZipFileGcos = new GzipCompressorOutputStream(targetGZipFileBos); // 采用commons-compress提供的方式進行壓縮. targetGZipFileGcos.write(IOUtils.toByteArray(sourceFileBis)); } catch (Exception ex) { logger.info( "GZipDiskUtil.compressByGZip." , ex); return false ; } finally { if (targetGZipFileGcos != null ) targetGZipFileGcos.close(); if (targetGZipFileBos != null ) targetGZipFileBos.close(); if (targetGZipFileFos != null ) targetGZipFileFos.close(); if (sourceFileBis != null ) sourceFileBis.close(); if (sourceFileFis != null ) sourceFileFis.close(); } return true ; } /** * 使用GZIP算法進行解壓. * @param sourceGZipFilePath 待解壓文件路徑. * @param targetFilePath 解壓后文件路徑. * @return 解壓是否成功. * @throws @throws Exception 解壓過程中可能發生的異常. */ public static boolean decompressByGZip(String sourceGZipFilePath, String targetFilePath) throws IOException { // 變量定義. FileInputStream sourceGZipFileFis = null ; BufferedInputStream sourceGZipFileBis = null ; FileOutputStream targetFileFos = null ; GzipCompressorInputStream sourceGZipFileGcis = null ; try { // 解壓變量初始化. sourceGZipFileFis = new FileInputStream( new File(sourceGZipFilePath)); sourceGZipFileBis = new BufferedInputStream(sourceGZipFileFis); sourceGZipFileGcis = new GzipCompressorInputStream(sourceGZipFileBis); targetFileFos = new FileOutputStream( new File(targetFilePath)); // 采用commons-compress提供的方式進行解壓. targetFileFos.write(IOUtils.toByteArray(sourceGZipFileGcis)); } catch (Exception ex) { logger.info( "GZipDiskUtil.decompressByGZip." , ex); return false ; } finally { if (sourceGZipFileGcis != null ) sourceGZipFileGcis.close(); if (sourceGZipFileBis != null ) sourceGZipFileBis.close(); if (sourceGZipFileFis != null ) sourceGZipFileFis.close(); if (targetFileFos != null ) targetFileFos.close(); } return true ; } } |
工具類測試
在Maven依賴引入正確的情況下,復制上面的代碼到項目中,修改package,可以直接使用,下面我們對工具類進行簡單測試。測試類代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
package com.arhorchin.securitit.compress.gzip; import com.arhorchin.securitit.compress.gzip.GZipDiskUtil; /** * @author Securitit. * @note GZipDiskUtil工具類測試. */ public class GZipDiskUtilTester { public static void main(String[] args) throws Exception { GZipDiskUtil.compressByTar( "C:/Users/Administrator/Downloads/個人文件/2020-07-13/files" , "C:/Users/Administrator/Downloads/個人文件/2020-07-13/disk.tar" ); GZipDiskUtil.compressByGZip( "C:/Users/Administrator/Downloads/個人文件/2020-07-13/disk.tar" , "C:/Users/Administrator/Downloads/個人文件/2020-07-13/disk.tar.gz" ); GZipDiskUtil.decompressByGZip( "C:/Users/Administrator/Downloads/個人文件/2020-07-13/disk.tar.gz" , "C:/Users/Administrator/Downloads/個人文件/2020-07-13/disk-untar.tar" ); GZipDiskUtil.decompressByTar( "C:/Users/Administrator/Downloads/個人文件/2020-07-13/disk-untar.tar" , "C:/Users/Administrator/Downloads/個人文件/2020-07-13/disk-untar" ); } } |
運行測試后,通過查看disk.tar、disk.tar.gz、disk-untar.tar和解壓的目錄,可以確認工具類運行結果無誤。
總結
1) 在小文件、文件數量較小且較為固定時,提倡使用內存壓縮和解壓方式。使用內存換時間,減少頻繁的磁盤操作。《Java GZip 基于內存實現壓縮和解壓》
2) 在大文件、文件數量較大時,提倡使用磁盤壓縮和解壓方式。過大文件對服務會造成過度的負載,磁盤壓縮和解壓可以緩解這種壓力。
原文鏈接:https://blog.csdn.net/securitit/article/details/108156025