Merge commit '712ddafb749aada41daab85c36ac12f657b2307e'
[nikiroo-utils.git] / TempFiles.java
CommitLineData
59864f77
NR
1package be.nikiroo.utils;
2
3import java.io.Closeable;
4import java.io.File;
5import 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 */
13public 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}