Javaでの圧縮と展開
1概要
このクイックチュートリアルでは、ファイルをアーカイブに圧縮する方法とアーカイブを解凍する方法について説明します。これらはすべて、Javaが提供するコアライブラリを使用しています。
これらのコアライブラリは
java.util.zip
パッケージの一部です –
2ファイルを圧縮
まず、単一のファイルを圧縮するという簡単な操作を見てみましょう。
ここでの例では、
test1.txt
という名前のファイルを
compressed.zip
.
+
という名前のアーカイブに圧縮します。
もちろん、最初にディスクからファイルにアクセスします。見てみましょう。
public class ZipFile {
public static void main(String[]args) throws IOException {
String sourceFile = "test1.txt";
FileOutputStream fos = new FileOutputStream("compressed.zip");
ZipOutputStream zipOut = new ZipOutputStream(fos);
File fileToZip = new File(sourceFile);
FileInputStream fis = new FileInputStream(fileToZip);
ZipEntry zipEntry = new ZipEntry(fileToZip.getName());
zipOut.putNextEntry(zipEntry);
byte[]bytes = new byte[1024];
int length;
while((length = fis.read(bytes)) >= 0) {
zipOut.write(bytes, 0, length);
}
zipOut.close();
fis.close();
fos.close();
}
}
3複数のファイルを圧縮
次に、複数のファイルを1つのzipファイルに圧縮する方法を見てみましょう。
test1.txt
と
test2.txt
を
multiCompressed.zip
に圧縮します。
public class ZipMultipleFiles {
public static void main(String[]args) throws IOException {
List<String> srcFiles = Arrays.asList("test1.txt", "test2.txt");
FileOutputStream fos = new FileOutputStream("multiCompressed.zip");
ZipOutputStream zipOut = new ZipOutputStream(fos);
for (String srcFile : srcFiles) {
File fileToZip = new File(srcFile);
FileInputStream fis = new FileInputStream(fileToZip);
ZipEntry zipEntry = new ZipEntry(fileToZip.getName());
zipOut.putNextEntry(zipEntry);
byte[]bytes = new byte[1024];
int length;
while((length = fis.read(bytes)) >= 0) {
zipOut.write(bytes, 0, length);
}
fis.close();
}
zipOut.close();
fos.close();
}
}
4ディレクトリを圧縮
それでは、ディレクトリ全体を圧縮する方法について説明しましょう。
zipTest
を
dirCompressed.zip
に配置します。
public class ZipDirectory {
public static void main(String[]args) throws IOException {
String sourceFile = "zipTest";
FileOutputStream fos = new FileOutputStream("dirCompressed.zip");
ZipOutputStream zipOut = new ZipOutputStream(fos);
File fileToZip = new File(sourceFile);
zipFile(fileToZip, fileToZip.getName(), zipOut);
zipOut.close();
fos.close();
}
private static void zipFile(File fileToZip, String fileName, ZipOutputStream zipOut) throws IOException {
if (fileToZip.isHidden()) {
return;
}
if (fileToZip.isDirectory()) {
if (fileName.endsWith("/")) {
zipOut.putNextEntry(new ZipEntry(fileName));
zipOut.closeEntry();
} else {
zipOut.putNextEntry(new ZipEntry(fileName + "/"));
zipOut.closeEntry();
}
File[]children = fileToZip.listFiles();
for (File childFile : children) {
zipFile(childFile, fileName + "/" + childFile.getName(), zipOut);
}
return;
}
FileInputStream fis = new FileInputStream(fileToZip);
ZipEntry zipEntry = new ZipEntry(fileName);
zipOut.putNextEntry(zipEntry);
byte[]bytes = new byte[1024];
int length;
while ((length = fis.read(bytes)) >= 0) {
zipOut.write(bytes, 0, length);
}
fis.close();
}
}
ご了承ください:
-
サブディレクトリを圧縮するために、それらを再帰的に繰り返します。
-
ディレクトリを見つけるたびに、その名前を子孫に追加します。
階層を保存するための
ZipEntry
の名前。
-
空のディレクトリごとにディレクトリエントリも作成します。
5アーカイブを解凍する
それでは、アーカイブを解凍してその内容を抽出しましょう。
この例では、
compressed.zip
を
unzipTest
という名前の新しいフォルダに解凍します。
みてみましょう:
public class UnzipFile {
public static void main(String[]args) throws IOException {
String fileZip = "src/main/resources/unzipTest/compressed.zip";
File destDir = new File("src/main/resources/unzipTest");
byte[]buffer = new byte[1024];
ZipInputStream zis = new ZipInputStream(new FileInputStream(fileZip));
ZipEntry zipEntry = zis.getNextEntry();
while (zipEntry != null) {
File newFile = newFile(destDir, zipEntry);
FileOutputStream fos = new FileOutputStream(newFile);
int len;
while ((len = zis.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
fos.close();
zipEntry = zis.getNextEntry();
}
zis.closeEntry();
zis.close();
}
public static File newFile(File destinationDir, ZipEntry zipEntry) throws IOException {
File destFile = new File(destinationDir, zipEntry.getName());
String destDirPath = destinationDir.getCanonicalPath();
String destFilePath = destFile.getCanonicalPath();
if (!destFilePath.startsWith(destDirPath + File.separator)) {
throw new IOException("Entry is outside of the target dir: " + zipEntry.getName());
}
return destFile;
}
}
もう1つ重要な点は、
newFile()
メソッドにあります。これらの方法は、ターゲットフォルダの外側のファイルシステムにファイルを書き込むことを防止します。この脆弱性はZip Slipと呼ばれ、https://snyk.io/research/zip-slip-の脆弱性。
6. 結論
このチュートリアルでは、ファイルの解凍と解凍の操作にJavaライブラリを簡単に使用する方法を説明しました。
これらの例の実装はhttps://github.com/eugenp/tutorials/tree/master/core-java-io[GitHubで公開]にあります – これはMavenベースのプロジェクトなので、インポートは簡単です。そのまま実行します。