Commit | Line | Data |
---|---|---|
59864f77 NR |
1 | package be.nikiroo.utils; |
2 | ||
3 | import java.io.Closeable; | |
4 | import java.io.File; | |
5 | import java.io.IOException; | |
6 | ||
7 | /** | |
8 | * A small utility class to generate auto-delete temporary files in a | |
9 | * centralised location. | |
10 | * | |
11 | * @author niki | |
12 | */ | |
13 | public class TempFiles implements Closeable { | |
82fcfcde NR |
14 | /** |
15 | * Root directory of this instance, owned by it, where all temporary files | |
16 | * must reside. | |
17 | */ | |
59864f77 NR |
18 | protected File root; |
19 | ||
20 | /** | |
21 | * Create a new {@link TempFiles} -- each instance is separate and have a | |
22 | * dedicated sub-directory in a shared temporary root. | |
23 | * <p> | |
24 | * The whole repository will be deleted on close (if you fail to call it, | |
82fcfcde | 25 | * the program will <b>try</b> to call it on JVM termination). |
59864f77 NR |
26 | * |
27 | * @param name | |
28 | * the instance name (will be <b>part</b> of the final directory | |
29 | * name) | |
30 | * | |
31 | * @throws IOException | |
32 | * in case of I/O error | |
33 | */ | |
34 | public TempFiles(String name) throws IOException { | |
82fcfcde NR |
35 | this(null, name); |
36 | } | |
37 | ||
38 | /** | |
39 | * Create a new {@link TempFiles} -- each instance is separate and have a | |
40 | * dedicated sub-directory in a given temporary root. | |
41 | * <p> | |
42 | * The whole repository will be deleted on close (if you fail to call it, | |
43 | * the program will <b>try</b> to call it on JVM termination). | |
44 | * <p> | |
45 | * Be careful, this instance will <b>own</b> the given root directory, and | |
46 | * will most probably delete all its files. | |
47 | * | |
48 | * @param base | |
49 | * the root base directory to use for all the temporary files of | |
50 | * this instance (if NULL, will be the default temporary | |
51 | * directory of the OS) | |
52 | * @param name | |
53 | * the instance name (will be <b>part</b> of the final directory | |
54 | * name) | |
55 | * | |
56 | * @throws IOException | |
57 | * in case of I/O error | |
58 | */ | |
59 | public TempFiles(File base, String name) throws IOException { | |
60 | if (base == null) { | |
61 | base = File.createTempFile(".temp", ""); | |
62 | } | |
63 | ||
64 | root = base; | |
65 | ||
223aa0d4 NR |
66 | if (root.exists()) { |
67 | IOUtils.deltree(root, true); | |
68 | } | |
59864f77 NR |
69 | |
70 | root = new File(root.getParentFile(), ".temp"); | |
71 | root.mkdir(); | |
72 | if (!root.exists()) { | |
73 | throw new IOException("Cannot create root directory: " + root); | |
74 | } | |
75 | ||
76 | root.deleteOnExit(); | |
77 | ||
78 | root = createTempFile(name); | |
79 | IOUtils.deltree(root, true); | |
80 | ||
81 | root.mkdir(); | |
82 | if (!root.exists()) { | |
83 | throw new IOException("Cannot create root subdirectory: " + root); | |
84 | } | |
85 | } | |
86 | ||
87 | /** | |
88 | * Create an auto-delete temporary file. | |
89 | * | |
90 | * @param name | |
91 | * a base for the final filename (only a <b>part</b> of said | |
92 | * filename) | |
93 | * | |
94 | * @return the newly created file | |
95 | * | |
96 | * @throws IOException | |
97 | * in case of I/O errors | |
98 | */ | |
99 | public synchronized File createTempFile(String name) throws IOException { | |
100 | name += "_"; | |
101 | while (name.length() < 3) { | |
102 | name += "_"; | |
103 | } | |
104 | ||
105 | while (true) { | |
106 | File tmp = File.createTempFile(name, ""); | |
107 | IOUtils.deltree(tmp, true); | |
108 | ||
109 | File test = new File(root, tmp.getName()); | |
110 | if (!test.exists()) { | |
111 | test.createNewFile(); | |
112 | if (!test.exists()) { | |
5cc94ce0 N |
113 | throw new IOException( |
114 | "Cannot create temporary file: " + test); | |
59864f77 NR |
115 | } |
116 | ||
117 | test.deleteOnExit(); | |
118 | return test; | |
119 | } | |
120 | } | |
121 | } | |
122 | ||
123 | /** | |
124 | * Create an auto-delete temporary directory. | |
125 | * <p> | |
126 | * Note that creating 2 temporary directories with the same name will result | |
127 | * in two <b>different</b> directories, even if the final name is the same | |
128 | * (the absolute path will be different). | |
129 | * | |
130 | * @param name | |
131 | * the actual directory name (not path) | |
132 | * | |
133 | * @return the newly created file | |
134 | * | |
135 | * @throws IOException | |
136 | * in case of I/O errors, or if the name was a path instead of a | |
137 | * name | |
138 | */ | |
139 | public synchronized File createTempDir(String name) throws IOException { | |
140 | File localRoot = createTempFile(name); | |
141 | IOUtils.deltree(localRoot, true); | |
142 | ||
143 | localRoot.mkdir(); | |
144 | if (!localRoot.exists()) { | |
145 | throw new IOException("Cannot create subdirectory: " + localRoot); | |
146 | } | |
147 | ||
148 | File dir = new File(localRoot, name); | |
149 | if (!dir.getName().equals(name)) { | |
150 | throw new IOException( | |
151 | "Cannot create temporary directory with a path, only names are allowed: " | |
152 | + dir); | |
153 | } | |
154 | ||
155 | dir.mkdir(); | |
156 | dir.deleteOnExit(); | |
157 | ||
158 | if (!dir.exists()) { | |
159 | throw new IOException("Cannot create subdirectory: " + dir); | |
160 | } | |
161 | ||
162 | return dir; | |
163 | } | |
164 | ||
165 | @Override | |
166 | public synchronized void close() throws IOException { | |
5cc94ce0 N |
167 | File root = this.root; |
168 | this.root = null; | |
169 | ||
170 | if (root != null) { | |
171 | IOUtils.deltree(root); | |
172 | ||
173 | // Since we allocate temp directories from a base point, | |
174 | // try and remove that base point | |
175 | root.getParentFile().delete(); // (only works if empty) | |
176 | } | |
59864f77 NR |
177 | } |
178 | ||
179 | @Override | |
180 | protected void finalize() throws Throwable { | |
181 | try { | |
182 | close(); | |
183 | } finally { | |
184 | super.finalize(); | |
185 | } | |
186 | } | |
187 | } |