/
FileUtil.java
133 lines (116 loc) · 3.84 KB
/
FileUtil.java
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
package mezz.jei.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
/**
* Utility to help read and write files in a crash-safe way using a temp file and a backup.
* If the game crashes while saving, the data saved by this utility should automatically recover.
*/
public final class FileUtil {
private FileUtil() {
}
public interface FileOperation {
void handle(File file) throws IOException;
}
public interface ZipInputFileOperation {
void handle(ZipInputStream zipInputStream) throws IOException;
}
public interface ZipOutputFileOperation {
void handle(ZipOutputStream zipOutputStream) throws IOException;
}
public static boolean writeFileSafely(final File file, final FileOperation fileOperation) {
final File fileNew = new File(file.getAbsolutePath());
final File fileBackup = new File(file.getAbsolutePath() + ".bak");
final File fileTemp = new File(file.getAbsolutePath() + ".tmp");
try {
if (fileTemp.exists() && !fileTemp.delete()) {
throw new IOException("Could not delete old temp file");
}
fileOperation.handle(fileTemp);
if (file.exists()) {
if (fileBackup.exists() && !fileBackup.delete()) {
throw new IOException("Could not delete old backup");
}
if (!file.renameTo(fileBackup)) {
throw new IOException("Could not backup file");
}
}
if (!fileTemp.renameTo(fileNew)) {
throw new IOException("Could not rename temp file");
}
if (fileBackup.exists() && !fileBackup.delete()) {
Log.error("Could not delete old backup file {}", fileBackup.getAbsoluteFile());
}
return true;
} catch (IOException e) {
Log.error("Failed to save file {}.", fileNew, e);
if (fileBackup.exists()) {
if (!fileNew.exists() || fileNew.delete()) {
if (fileBackup.renameTo(fileNew)) {
Log.info("Restored file from backup.");
return false;
}
}
Log.error("Failed to restore file from backup file {}", fileBackup.getAbsoluteFile());
}
return false;
}
}
public static void readFileSafely(final File file, final FileOperation fileOperation) {
if (!file.exists()) {
final File fileBackup = new File(file.getAbsolutePath() + ".bak");
if (fileBackup.exists()) {
if (fileBackup.renameTo(file)) {
Log.info("Restored file from backup.");
}
}
}
if (file.exists()) {
try {
fileOperation.handle(file);
} catch (IOException e) {
Log.error("Failed to read file {}.", file, e);
}
}
}
public static void readZipFileSafely(final File file, final String zipEntryName, final ZipInputFileOperation fileOperation) {
FileUtil.readFileSafely(file, new FileOperation() {
@Override
public void handle(File file) throws IOException {
final ZipInputStream zipInput = new ZipInputStream(new FileInputStream(file));
if (FileUtil.getZipEntry(zipInput, zipEntryName)) {
fileOperation.handle(zipInput);
zipInput.close();
}
}
});
}
public static boolean writeZipFileSafely(final File file, final String zipEntryName, final ZipOutputFileOperation fileOperation) {
return FileUtil.writeFileSafely(file, new FileUtil.FileOperation() {
@Override
public void handle(File file) throws IOException {
ZipOutputStream zipOutput = new ZipOutputStream(new FileOutputStream(file));
zipOutput.putNextEntry(new ZipEntry(zipEntryName));
fileOperation.handle(zipOutput);
zipOutput.closeEntry();
zipOutput.close();
}
});
}
public static boolean getZipEntry(ZipInputStream zipInputStream, String zipEntryName) throws IOException {
while (true) {
ZipEntry zipEntry = zipInputStream.getNextEntry();
if (zipEntry != null) {
if (zipEntry.getName().equals(zipEntryName)) {
return true;
}
} else {
return false;
}
}
}
}