优化 ArchiveFileTree (#4177)

This commit is contained in:
Glavo
2025-08-02 19:33:44 +08:00
committed by GitHub
parent 6230b436ad
commit 9969dc60c5
4 changed files with 134 additions and 20 deletions

View File

@@ -66,7 +66,7 @@ public final class CompressingUtils {
cd.reset();
byte[] ba = entry.getRawName();
int clen = (int)(ba.length * cd.maxCharsPerByte());
int clen = (int) (ba.length * cd.maxCharsPerByte());
if (clen == 0) continue;
if (clen <= cb.capacity())
cb.clear();
@@ -129,7 +129,19 @@ public final class CompressingUtils {
}
public static ZipArchiveReader openZipFile(Path zipFile) throws IOException {
return new ZipArchiveReader(Files.newByteChannel(zipFile));
ZipArchiveReader zipReader = new ZipArchiveReader(Files.newByteChannel(zipFile));
Charset suitableEncoding;
try {
suitableEncoding = findSuitableEncoding(zipReader);
if (suitableEncoding == StandardCharsets.UTF_8)
return zipReader;
} catch (Throwable e) {
IOUtils.closeQuietly(zipReader, e);
throw e;
}
zipReader.close();
return new ZipArchiveReader(Files.newByteChannel(zipFile), suitableEncoding);
}
public static ZipArchiveReader openZipFile(Path zipFile, Charset charset) throws IOException {
@@ -221,9 +233,9 @@ public final class CompressingUtils {
* Read the text content of a file in zip.
*
* @param zipFile the zip file
* @param name the location of the text in zip file, something like A/B/C/D.txt
* @throws IOException if the file is not a valid zip file.
* @param name the location of the text in zip file, something like A/B/C/D.txt
* @return the plain text content of given file.
* @throws IOException if the file is not a valid zip file.
*/
public static String readTextZipEntry(File zipFile, String name) throws IOException {
try (ZipArchiveReader s = new ZipArchiveReader(zipFile.toPath())) {
@@ -235,9 +247,9 @@ public final class CompressingUtils {
* Read the text content of a file in zip.
*
* @param zipFile the zip file
* @param name the location of the text in zip file, something like A/B/C/D.txt
* @throws IOException if the file is not a valid zip file.
* @param name the location of the text in zip file, something like A/B/C/D.txt
* @return the plain text content of given file.
* @throws IOException if the file is not a valid zip file.
*/
public static String readTextZipEntry(ZipArchiveReader zipFile, String name) throws IOException {
return IOUtils.readFullyAsString(zipFile.getInputStream(zipFile.getEntry(name)));
@@ -247,9 +259,9 @@ public final class CompressingUtils {
* Read the text content of a file in zip.
*
* @param zipFile the zip file
* @param name the location of the text in zip file, something like A/B/C/D.txt
* @throws IOException if the file is not a valid zip file.
* @param name the location of the text in zip file, something like A/B/C/D.txt
* @return the plain text content of given file.
* @throws IOException if the file is not a valid zip file.
*/
public static String readTextZipEntry(Path zipFile, String name, Charset encoding) throws IOException {
try (ZipArchiveReader s = openZipFile(zipFile, encoding)) {

View File

@@ -19,6 +19,9 @@ package org.jackhuang.hmcl.util.tree;
import kala.compress.archivers.ArchiveEntry;
import kala.compress.archivers.zip.ZipArchiveReader;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.UnmodifiableView;
import java.io.Closeable;
import java.io.IOException;
@@ -48,7 +51,7 @@ public abstract class ArchiveFileTree<F, E extends ArchiveEntry> implements Clos
}
protected final F file;
protected final Dir<E> root = new Dir<>();
protected final Dir<E> root = new Dir<>("");
public ArchiveFileTree(F file) {
this.file = file;
@@ -62,7 +65,7 @@ public abstract class ArchiveFileTree<F, E extends ArchiveEntry> implements Clos
return root;
}
public void addEntry(E entry) throws IOException {
protected void addEntry(E entry) throws IOException {
String[] path = entry.getName().split("/");
Dir<E> dir = root;
@@ -78,7 +81,7 @@ public abstract class ArchiveFileTree<F, E extends ArchiveEntry> implements Clos
throw new IOException("A file and a directory have the same name: " + entry.getName());
}
dir = dir.subDirs.computeIfAbsent(item, name -> new Dir<>());
dir = dir.subDirs.computeIfAbsent(item, Dir::new);
}
if (entry.isDirectory()) {
@@ -113,16 +116,33 @@ public abstract class ArchiveFileTree<F, E extends ArchiveEntry> implements Clos
public abstract void close() throws IOException;
public static final class Dir<E extends ArchiveEntry> {
E entry;
private final String name;
private E entry;
final Map<String, Dir<E>> subDirs = new HashMap<>();
final Map<String, E> files = new HashMap<>();
public Map<String, Dir<E>> getSubDirs() {
public Dir(String name) {
this.name = name;
}
public boolean isRoot() {
return name.isEmpty();
}
public @NotNull String getName() {
return name;
}
public @Nullable E getEntry() {
return entry;
}
public @NotNull @UnmodifiableView Map<String, Dir<E>> getSubDirs() {
return subDirs;
}
public Map<String, E> getFiles() {
public @NotNull @UnmodifiableView Map<String, E> getFiles() {
return files;
}
}

View File

@@ -19,6 +19,7 @@ package org.jackhuang.hmcl.util.tree;
import kala.compress.archivers.zip.ZipArchiveEntry;
import kala.compress.archivers.zip.ZipArchiveReader;
import org.jackhuang.hmcl.util.io.IOUtils;
import java.io.IOException;
import java.io.InputStream;
@@ -27,25 +28,30 @@ import java.io.InputStream;
* @author Glavo
*/
public final class ZipFileTree extends ArchiveFileTree<ZipArchiveReader, ZipArchiveEntry> {
private final boolean closeReader;
public ZipFileTree(ZipArchiveReader file) throws IOException {
this(file, true);
}
public ZipFileTree(ZipArchiveReader file, boolean closeReader) throws IOException {
super(file);
this.closeReader = closeReader;
try {
for (ZipArchiveEntry zipArchiveEntry : file.getEntries()) {
addEntry(zipArchiveEntry);
}
} catch (Throwable e) {
try {
file.close();
} catch (Throwable e2) {
e.addSuppressed(e2);
}
if (closeReader)
IOUtils.closeQuietly(file, e);
throw e;
}
}
@Override
public void close() throws IOException {
file.close();
if (closeReader)
file.close();
}
@Override