New TempFiles and Image now uses it instead of mem
[fanfix.git] / src / be / nikiroo / utils / IOUtils.java
CommitLineData
ec1f3444
NR
1package be.nikiroo.utils;
2
3import java.io.BufferedReader;
80500544 4import java.io.ByteArrayOutputStream;
ec1f3444
NR
5import java.io.File;
6import java.io.FileInputStream;
7import java.io.FileOutputStream;
ec1f3444
NR
8import java.io.FileWriter;
9import java.io.IOException;
10import java.io.InputStream;
3f8349b7 11import java.io.InputStreamReader;
ec1f3444 12import java.io.OutputStream;
59864f77
NR
13import java.util.ArrayList;
14import java.util.List;
ec1f3444
NR
15import java.util.zip.ZipEntry;
16import java.util.zip.ZipOutputStream;
17
18/**
72c32e88 19 * This class offer some utilities based around Streams.
ec1f3444
NR
20 *
21 * @author niki
22 */
23public class IOUtils {
24 /**
25 * Write the data to the given {@link File}.
26 *
27 * @param in
28 * the data source
29 * @param target
30 * the target {@link File}
31 *
32 * @throws IOException
33 * in case of I/O error
34 */
35 public static void write(InputStream in, File target) throws IOException {
36 OutputStream out = new FileOutputStream(target);
37 try {
38 write(in, out);
39 } finally {
40 out.close();
41 }
42 }
43
44 /**
45 * Write the data to the given {@link OutputStream}.
46 *
47 * @param in
48 * the data source
db31c358 49 * @param out
ec1f3444
NR
50 * the target {@link OutputStream}
51 *
52 * @throws IOException
53 * in case of I/O error
54 */
55 public static void write(InputStream in, OutputStream out)
56 throws IOException {
57 byte buffer[] = new byte[4069];
58 for (int len = 0; (len = in.read(buffer)) > 0;) {
59 out.write(buffer, 0, len);
60 }
61 }
62
63 /**
64 * Recursively Add a {@link File} (which can thus be a directory, too) to a
65 * {@link ZipOutputStream}.
66 *
67 * @param zip
68 * the stream
69 * @param base
70 * the path to prepend to the ZIP info before the actual
71 * {@link File} path
72 * @param target
73 * the source {@link File} (which can be a directory)
74 * @param targetIsRoot
75 * FALSE if we need to add a {@link ZipEntry} for base/target,
76 * TRUE to add it at the root of the ZIP
77 *
78 * @throws IOException
79 * in case of I/O error
80 */
81 public static void zip(ZipOutputStream zip, String base, File target,
82 boolean targetIsRoot) throws IOException {
83 if (target.isDirectory()) {
84 if (!targetIsRoot) {
85 if (base == null || base.isEmpty()) {
86 base = target.getName();
87 } else {
88 base += "/" + target.getName();
89 }
90 zip.putNextEntry(new ZipEntry(base + "/"));
91 }
92 for (File file : target.listFiles()) {
93 zip(zip, base, file, false);
94 }
95 } else {
96 if (base == null || base.isEmpty()) {
97 base = target.getName();
98 } else {
99 base += "/" + target.getName();
100 }
101 zip.putNextEntry(new ZipEntry(base));
102 FileInputStream in = new FileInputStream(target);
103 try {
104 IOUtils.write(in, zip);
105 } finally {
106 in.close();
107 }
108 }
109 }
110
111 /**
112 * Zip the given source into dest.
113 *
114 * @param src
115 * the source {@link File} (which can be a directory)
116 * @param dest
117 * the destination <tt>.zip</tt> file
db31c358 118 * @param srcIsRoot
ec1f3444
NR
119 * FALSE if we need to add a {@link ZipEntry} for src, TRUE to
120 * add it at the root of the ZIP
121 *
122 * @throws IOException
123 * in case of I/O error
124 */
125 public static void zip(File src, File dest, boolean srcIsRoot)
126 throws IOException {
127 OutputStream out = new FileOutputStream(dest);
128 try {
129 ZipOutputStream zip = new ZipOutputStream(out);
130 try {
131 IOUtils.zip(zip, "", src, srcIsRoot);
132 } finally {
133 zip.close();
134 }
135 } finally {
136 out.close();
137 }
138 }
139
140 /**
141 * Write the {@link String} content to {@link File}.
142 *
143 * @param dir
144 * the directory where to write the {@link File}
145 * @param filename
146 * the {@link File} name
147 * @param content
148 * the content
149 *
150 * @throws IOException
151 * in case of I/O error
152 */
153 public static void writeSmallFile(File dir, String filename, String content)
154 throws IOException {
155 if (!dir.exists()) {
156 dir.mkdirs();
157 }
158
159 FileWriter writerVersion = new FileWriter(new File(dir, filename));
160 try {
161 writerVersion.write(content);
162 } finally {
163 writerVersion.close();
164 }
165 }
166
167 /**
168 * Read the whole {@link File} content into a {@link String}.
169 *
170 * @param file
171 * the {@link File}
172 *
173 * @return the content
174 *
175 * @throws IOException
176 * in case of I/O error
177 */
178 public static String readSmallFile(File file) throws IOException {
3f8349b7
NR
179 InputStream stream = new FileInputStream(file);
180 try {
181 return readSmallStream(stream);
182 } finally {
183 stream.close();
184 }
185 }
186
187 /**
188 * Read the whole {@link InputStream} content into a {@link String}.
189 *
190 * @param stream
191 * the {@link InputStream}
192 *
193 * @return the content
194 *
195 * @throws IOException
196 * in case of I/O error
197 */
198 public static String readSmallStream(InputStream stream) throws IOException {
530d4062
NR
199 // do NOT close the reader, or the related stream will be closed, too
200 // reader.close();
3f8349b7
NR
201 BufferedReader reader = new BufferedReader(
202 new InputStreamReader(stream));
530d4062
NR
203
204 StringBuilder builder = new StringBuilder();
205 for (String line = reader.readLine(); line != null; line = reader
206 .readLine()) {
207 builder.append(line);
208 builder.append("\n");
ec1f3444 209 }
530d4062
NR
210
211 return builder.toString();
ec1f3444
NR
212 }
213
59864f77
NR
214 /**
215 * Recursively delete the given {@link File}, which may of course also be a
216 * directory.
217 * <p>
218 * Will either silently continue or throw an exception in case of error,
219 * depending upon the parameters.
220 *
221 * @param target
222 * the target to delete
223 * @param exception
224 * TRUE to throw an {@link IOException} in case of error, FALSE
225 * to silently continue
226 *
227 * @return TRUE if all files were deleted, FALSE if an error occurred
228 *
229 * @throws IOException
230 * if an error occurred and the parameters allow an exception to
231 * be thrown
232 */
233 public static boolean deltree(File target, boolean exception)
234 throws IOException {
235 List<File> list = deltree(target, null);
236 if (exception && !list.isEmpty()) {
237 String slist = "";
238 for (File file : list) {
239 slist += "\n" + file.getPath();
240 }
241
242 throw new IOException("Cannot delete all the files from: <" //
243 + target + ">:" + slist);
244 }
245
246 return list.isEmpty();
247 }
248
ec1f3444
NR
249 /**
250 * Recursively delete the given {@link File}, which may of course also be a
251 * directory.
252 * <p>
253 * Will silently continue in case of error.
254 *
255 * @param target
256 * the target to delete
59864f77
NR
257 *
258 * @return TRUE if all files were deleted, FALSE if an error occurred
259 */
260 public static boolean deltree(File target) {
261 return deltree(target, null).isEmpty();
262 }
263
264 /**
265 * Recursively delete the given {@link File}, which may of course also be a
266 * directory.
267 * <p>
268 * Will collect all {@link File} that cannot be deleted in the given
269 * accumulator.
270 *
271 * @param target
272 * the target to delete
273 * @param errorAcc
274 * the accumulator to use for errors, or NULL to create a new one
275 *
276 * @return the errors accumulator
ec1f3444 277 */
59864f77
NR
278 public static List<File> deltree(File target, List<File> errorAcc) {
279 if (errorAcc == null) {
280 errorAcc = new ArrayList<File>();
281 }
282
7ee9568b
NR
283 File[] files = target.listFiles();
284 if (files != null) {
285 for (File file : files) {
59864f77 286 errorAcc = deltree(file, errorAcc);
ec1f3444
NR
287 }
288 }
289
290 if (!target.delete()) {
59864f77 291 errorAcc.add(target);
ec1f3444 292 }
59864f77
NR
293
294 return errorAcc;
ec1f3444 295 }
b607df60 296
16d59378
NR
297 /**
298 * Open the given /-separated resource (from the binary root).
299 *
300 * @param name
301 * the resource name
302 *
303 * @return the opened resource if found, NLL if not
304 */
305 public static InputStream openResource(String name) {
306 ClassLoader loader = IOUtils.class.getClassLoader();
307 if (loader == null) {
308 loader = ClassLoader.getSystemClassLoader();
309 }
310
311 return loader.getResourceAsStream(name);
312 }
80500544
NR
313
314 /**
315 * Return a resetable {@link InputStream} from this stream, and reset it.
316 *
317 * @param in
318 * the input stream
319 * @return the resetable stream, which <b>may</b> be the same
320 *
321 * @throws IOException
322 * in case of I/O error
323 */
324 public static InputStream forceResetableStream(InputStream in)
325 throws IOException {
326 MarkableFileInputStream tmpIn = null;
327 File tmp = null;
328
329 boolean resetable = in.markSupported();
330 if (resetable) {
331 try {
332 in.reset();
333 } catch (IOException e) {
334 resetable = false;
335 }
336 }
337
338 if (resetable) {
339 return in;
340 }
341
342 tmp = File.createTempFile(".tmp-stream", ".tmp");
343 try {
344 write(in, tmp);
345 tmpIn = new MarkableFileInputStream(new FileInputStream(tmp));
346 return tmpIn;
347 } finally {
348 try {
349 if (tmpIn != null) {
350 tmpIn.close();
351 }
352 } finally {
353 tmp.delete();
354 }
355 }
356 }
357
358 /**
359 * Convert the {@link InputStream} into a byte array.
360 *
361 * @param in
362 * the input stream
363 *
364 * @return the array
365 *
366 * @throws IOException
367 * in case of I/O error
368 */
369 public static byte[] toByteArray(InputStream in) throws IOException {
370 ByteArrayOutputStream out = new ByteArrayOutputStream();
371 write(in, out);
372
373 byte[] array = out.toByteArray();
374 out.close();
375
376 return array;
377 }
ec1f3444 378}