Add comments to FileUtils and IOUtils

This commit is contained in:
huanghongxun 2019-02-23 23:42:05 +08:00
parent a388450f94
commit 9add2387b9
8 changed files with 91 additions and 38 deletions

View File

@ -225,16 +225,16 @@ public class LibraryDownloadTask extends Task {
int x = decompressed.length; int x = decompressed.length;
int len = decompressed[(x - 8)] & 0xFF | (decompressed[(x - 7)] & 0xFF) << 8 | (decompressed[(x - 6)] & 0xFF) << 16 | (decompressed[(x - 5)] & 0xFF) << 24; int len = decompressed[(x - 8)] & 0xFF | (decompressed[(x - 7)] & 0xFF) << 8 | (decompressed[(x - 6)] & 0xFF) << 16 | (decompressed[(x - 5)] & 0xFF) << 24;
File temp = FileUtils.createTempFile("minecraft", ".pack"); Path temp = Files.createTempFile("minecraft", ".pack");
byte[] checksums = Arrays.copyOfRange(decompressed, decompressed.length - len - 8, decompressed.length - 8); byte[] checksums = Arrays.copyOfRange(decompressed, decompressed.length - len - 8, decompressed.length - 8);
OutputStream out = new FileOutputStream(temp); try (OutputStream out = Files.newOutputStream(temp)) {
out.write(decompressed, 0, decompressed.length - len - 8); out.write(decompressed, 0, decompressed.length - len - 8);
out.close(); }
try (FileOutputStream jarBytes = new FileOutputStream(dest); JarOutputStream jos = new JarOutputStream(jarBytes)) { try (FileOutputStream jarBytes = new FileOutputStream(dest); JarOutputStream jos = new JarOutputStream(jarBytes)) {
Pack200.newUnpacker().unpack(temp, jos); Pack200.newUnpacker().unpack(temp.toFile(), jos);
JarEntry checksumsFile = new JarEntry("checksums.sha1"); JarEntry checksumsFile = new JarEntry("checksums.sha1");
checksumsFile.setTime(0L); checksumsFile.setTime(0L);
@ -243,6 +243,6 @@ public class LibraryDownloadTask extends Task {
jos.closeEntry(); jos.closeEntry();
} }
temp.delete(); Files.delete(temp);
} }
} }

View File

@ -53,8 +53,6 @@ public final class VersionJsonSaveTask extends TaskResult<Version> {
@Override @Override
public void execute() throws Exception { public void execute() throws Exception {
File json = repository.getVersionJson(version.getId()).getAbsoluteFile(); File json = repository.getVersionJson(version.getId()).getAbsoluteFile();
if (!FileUtils.makeFile(json))
throw new IOException("Cannot create file " + json);
FileUtils.writeText(json, JsonUtils.GSON.toJson(version)); FileUtils.writeText(json, JsonUtils.GSON.toJson(version));
} }
} }

View File

@ -168,8 +168,8 @@ public class DefaultGameRepository implements GameRepository {
versions.remove(id); versions.remove(id);
if (FileUtils.isMovingToTrashSupported()) { if (FileUtils.isMovingToTrashSupported() && FileUtils.moveToTrash(removedFile)) {
return FileUtils.moveToTrash(removedFile); return true;
} }
// remove json files first to ensure HMCL will not recognize this folder as a valid version. // remove json files first to ensure HMCL will not recognize this folder as a valid version.

View File

@ -23,7 +23,7 @@ import com.google.gson.reflect.TypeToken;
import org.jackhuang.hmcl.util.*; import org.jackhuang.hmcl.util.*;
import org.jackhuang.hmcl.util.gson.JsonUtils; import org.jackhuang.hmcl.util.gson.JsonUtils;
import org.jackhuang.hmcl.util.io.CompressingUtils; import org.jackhuang.hmcl.util.io.CompressingUtils;
import org.jackhuang.hmcl.util.io.IOUtils; import org.jackhuang.hmcl.util.io.FileUtils;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -119,7 +119,7 @@ public final class ForgeModMetadata {
Path mcmod = fs.getPath("mcmod.info"); Path mcmod = fs.getPath("mcmod.info");
if (Files.notExists(mcmod)) if (Files.notExists(mcmod))
throw new IOException("File " + modFile + " is not a Forge mod."); throw new IOException("File " + modFile + " is not a Forge mod.");
List<ForgeModMetadata> modList = JsonUtils.GSON.fromJson(IOUtils.readFullyAsString(Files.newInputStream(mcmod)), List<ForgeModMetadata> modList = JsonUtils.GSON.fromJson(FileUtils.readText(mcmod),
new TypeToken<List<ForgeModMetadata>>() { new TypeToken<List<ForgeModMetadata>>() {
}.getType()); }.getType());
if (modList == null || modList.isEmpty()) if (modList == null || modList.isEmpty())

View File

@ -33,6 +33,7 @@ import java.io.RandomAccessFile;
import java.math.BigInteger; import java.math.BigInteger;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URL; import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.util.Optional; import java.util.Optional;
@ -212,7 +213,7 @@ public class FileDownloadTask extends Task {
break; break;
} }
File temp = null; Path temp = null;
try { try {
updateProgress(0); updateProgress(0);
@ -242,15 +243,15 @@ public class FileDownloadTask extends Task {
if (!FileUtils.makeDirectory(file.getAbsoluteFile().getParentFile())) if (!FileUtils.makeDirectory(file.getAbsoluteFile().getParentFile()))
throw new IOException("Could not make directory " + file.getAbsoluteFile().getParent()); throw new IOException("Could not make directory " + file.getAbsoluteFile().getParent());
temp = FileUtils.createTempFile(); temp = Files.createTempFile(null, null);
rFile = new RandomAccessFile(temp, "rw"); rFile = new RandomAccessFile(temp.toFile(), "rw");
MessageDigest digest = integrityCheck == null ? null : integrityCheck.createDigest(); MessageDigest digest = integrityCheck == null ? null : integrityCheck.createDigest();
stream = con.getInputStream(); stream = con.getInputStream();
int lastDownloaded = 0, downloaded = 0; int lastDownloaded = 0, downloaded = 0;
long lastTime = System.currentTimeMillis(); long lastTime = System.currentTimeMillis();
byte buffer[] = new byte[IOUtils.DEFAULT_BUFFER_SIZE]; byte[] buffer = new byte[IOUtils.DEFAULT_BUFFER_SIZE];
while (true) { while (true) {
if (Thread.interrupted()) { if (Thread.interrupted()) {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
@ -283,16 +284,15 @@ public class FileDownloadTask extends Task {
// Restore temp file to original name. // Restore temp file to original name.
if (Thread.interrupted()) { if (Thread.interrupted()) {
temp.delete(); temp.toFile().delete();
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
break; break;
} else { } else {
if (file.exists() && !file.delete()) Files.deleteIfExists(file.toPath());
throw new IOException("Unable to delete existent file " + file);
if (!FileUtils.makeDirectory(file.getAbsoluteFile().getParentFile())) if (!FileUtils.makeDirectory(file.getAbsoluteFile().getParentFile()))
throw new IOException("Unable to make parent directory " + file); throw new IOException("Unable to make parent directory " + file);
try { try {
FileUtils.moveFile(temp, file); FileUtils.moveFile(temp.toFile(), file);
} catch (Exception e) { } catch (Exception e) {
throw new IOException("Unable to move temp file from " + temp + " to " + file, e); throw new IOException("Unable to move temp file from " + temp + " to " + file, e);
} }
@ -321,7 +321,7 @@ public class FileDownloadTask extends Task {
return; return;
} catch (IOException | IllegalStateException e) { } catch (IOException | IllegalStateException e) {
if (temp != null) if (temp != null)
temp.delete(); temp.toFile().delete();
exception = e; exception = e;
} finally { } finally {
closeFiles(); closeFiles();

View File

@ -293,6 +293,11 @@ public abstract class Task {
return new TaskResult<R>() { return new TaskResult<R>() {
TaskResult<R> then; TaskResult<R> then;
@Override
public Collection<? extends Task> getDependents() {
return Collections.singleton(Task.this);
}
@Override @Override
public void execute() throws Exception { public void execute() throws Exception {
then = taskSupplier.get().storeTo(this::setResult); then = taskSupplier.get().storeTo(this::setResult);

View File

@ -116,14 +116,43 @@ public final class FileUtils {
return new String(Files.readAllBytes(file), charset); return new String(Files.readAllBytes(file), charset);
} }
/**
* Write plain text to file. Characters are encoded into bytes using UTF-8.
*
* We don't care about platform difference of line separator. Because readText accept all possibilities of line separator.
* It will create the file if it does not exist, or truncate the existing file to empty for rewriting.
* All characters in text will be written into the file in binary format. Existing data will be erased.
* @param file the path to the file
* @param text the text being written to file
* @throws IOException if an I/O error occurs
*/
public static void writeText(File file, String text) throws IOException { public static void writeText(File file, String text) throws IOException {
writeText(file, text, UTF_8); writeText(file, text, UTF_8);
} }
/**
* Write plain text to file.
*
* We don't care about platform difference of line separator. Because readText accept all possibilities of line separator.
* It will create the file if it does not exist, or truncate the existing file to empty for rewriting.
* All characters in text will be written into the file in binary format. Existing data will be erased.
* @param file the path to the file
* @param text the text being written to file
* @param charset the charset to use for encoding
* @throws IOException if an I/O error occurs
*/
public static void writeText(File file, String text, Charset charset) throws IOException { public static void writeText(File file, String text, Charset charset) throws IOException {
writeBytes(file, text.getBytes(charset)); writeBytes(file, text.getBytes(charset));
} }
/**
* Write byte array to file.
* It will create the file if it does not exist, or truncate the existing file to empty for rewriting.
* All bytes in byte array will be written into the file in binary format. Existing data will be erased.
* @param file the path to the file
* @param array the data being written to file
* @throws IOException if an I/O error occurs
*/
public static void writeBytes(File file, byte[] array) throws IOException { public static void writeBytes(File file, byte[] array) throws IOException {
Files.createDirectories(file.toPath().getParent()); Files.createDirectories(file.toPath().getParent());
Files.write(file.toPath(), array); Files.write(file.toPath(), array);
@ -153,6 +182,14 @@ public final class FileUtils {
} }
} }
/**
* Copy directory.
* Paths of all files relative to source directory will be the same as the ones relative to destination directory.
*
* @param src the source directory.
* @param dest the destination directory, which will be created if not existing.
* @throws IOException if an I/O error occurs.
*/
public static void copyDirectory(Path src, Path dest) throws IOException { public static void copyDirectory(Path src, Path dest) throws IOException {
Files.walkFileTree(src, new SimpleFileVisitor<Path>(){ Files.walkFileTree(src, new SimpleFileVisitor<Path>(){
@Override @Override
@ -173,6 +210,20 @@ public final class FileUtils {
}); });
} }
/**
* Move file to trash.
*
* This method is only implemented in Java 9. Please check we are using Java 9 by invoking isMovingToTrashSupported.
* Example:
* <pre>{@code
* if (FileUtils.isMovingToTrashSupported()) {
* FileUtils.moveToTrash(file);
* }
* }</pre>
* @param file the file being moved to trash.
* @see FileUtils#isMovingToTrashSupported()
* @return false if moveToTrash does not exist, or platform does not support Desktop.Action.MOVE_TO_TRASH
*/
public static boolean moveToTrash(File file) { public static boolean moveToTrash(File file) {
try { try {
java.awt.Desktop desktop = java.awt.Desktop.getDesktop(); java.awt.Desktop desktop = java.awt.Desktop.getDesktop();
@ -314,20 +365,4 @@ public final class FileUtils {
result.add(it); result.add(it);
return result; return result;
} }
public static File createTempFile() throws IOException {
return createTempFile("tmp");
}
public static File createTempFile(String prefix) throws IOException {
return createTempFile(prefix, null);
}
public static File createTempFile(String prefix, String suffix) throws IOException {
return createTempFile(prefix, suffix, null);
}
public static File createTempFile(String prefix, String suffix, File directory) throws IOException {
return File.createTempFile(prefix, suffix, directory);
}
} }

View File

@ -21,8 +21,9 @@ import java.io.*;
import java.nio.charset.Charset; import java.nio.charset.Charset;
/** /**
* This utility class consists of some util methods operating on InputStream/OutputStream.
* *
* @author huang * @author huangyuhui
*/ */
public final class IOUtils { public final class IOUtils {
@ -31,12 +32,26 @@ public final class IOUtils {
public static final int DEFAULT_BUFFER_SIZE = 8 * 1024; public static final int DEFAULT_BUFFER_SIZE = 8 * 1024;
/**
* Read all bytes to a buffer from given input stream. The stream will not be closed.
*
* @param stream the InputStream being read.
* @return all bytes read from the stream
* @throws IOException if an I/O error occurs.
*/
public static byte[] readFullyWithoutClosing(InputStream stream) throws IOException { public static byte[] readFullyWithoutClosing(InputStream stream) throws IOException {
ByteArrayOutputStream result = new ByteArrayOutputStream(); ByteArrayOutputStream result = new ByteArrayOutputStream();
copyTo(stream, result); copyTo(stream, result);
return result.toByteArray(); return result.toByteArray();
} }
/**
* Read all bytes to a buffer from given input stream, and close the input stream finally.
*
* @param stream the InputStream being read, closed finally.
* @return all bytes read from the stream
* @throws IOException if an I/O error occurs.
*/
public static ByteArrayOutputStream readFully(InputStream stream) throws IOException { public static ByteArrayOutputStream readFully(InputStream stream) throws IOException {
try (InputStream is = stream) { try (InputStream is = stream) {
ByteArrayOutputStream result = new ByteArrayOutputStream(); ByteArrayOutputStream result = new ByteArrayOutputStream();