1 package be
.nikiroo
.utils
;
3 import java
.io
.ByteArrayOutputStream
;
5 import java
.io
.FileInputStream
;
6 import java
.io
.FileOutputStream
;
7 import java
.io
.IOException
;
8 import java
.io
.InputStream
;
9 import java
.io
.OutputStream
;
10 import java
.util
.ArrayList
;
11 import java
.util
.List
;
12 import java
.util
.zip
.ZipEntry
;
13 import java
.util
.zip
.ZipInputStream
;
14 import java
.util
.zip
.ZipOutputStream
;
16 import be
.nikiroo
.utils
.streams
.MarkableFileInputStream
;
19 * This class offer some utilities based around Streams and Files.
23 public class IOUtils
{
25 * Write the data to the given {@link File}.
30 * the target {@link File}
33 * in case of I/O error
35 public static void write(InputStream in
, File target
) throws IOException
{
36 OutputStream out
= new FileOutputStream(target
);
45 * Write the data to the given {@link OutputStream}.
50 * the target {@link OutputStream}
53 * in case of I/O error
55 public static void write(InputStream in
, OutputStream out
)
57 byte buffer
[] = new byte[4096];
58 int len
= in
.read(buffer
);
60 out
.write(buffer
, 0, len
);
61 len
= in
.read(buffer
);
66 * Recursively Add a {@link File} (which can thus be a directory, too) to a
67 * {@link ZipOutputStream}.
72 * the path to prepend to the ZIP info before the actual
75 * the source {@link File} (which can be a directory)
77 * FALSE if we need to add a {@link ZipEntry} for base/target,
78 * TRUE to add it at the root of the ZIP
81 * in case of I/O error
83 public static void zip(ZipOutputStream zip
, String base
, File target
,
84 boolean targetIsRoot
) throws IOException
{
85 if (target
.isDirectory()) {
87 if (base
== null || base
.isEmpty()) {
88 base
= target
.getName();
90 base
+= "/" + target
.getName();
92 zip
.putNextEntry(new ZipEntry(base
+ "/"));
95 File
[] files
= target
.listFiles();
97 for (File file
: files
) {
98 zip(zip
, base
, file
, false);
102 if (base
== null || base
.isEmpty()) {
103 base
= target
.getName();
105 base
+= "/" + target
.getName();
107 zip
.putNextEntry(new ZipEntry(base
));
108 FileInputStream in
= new FileInputStream(target
);
110 IOUtils
.write(in
, zip
);
118 * Zip the given source into dest.
121 * the source {@link File} (which can be a directory)
123 * the destination <tt>.zip</tt> file
125 * FALSE if we need to add a {@link ZipEntry} for src, TRUE to
126 * add it at the root of the ZIP
128 * @throws IOException
129 * in case of I/O error
131 public static void zip(File src
, File dest
, boolean srcIsRoot
)
133 OutputStream out
= new FileOutputStream(dest
);
135 ZipOutputStream zip
= new ZipOutputStream(out
);
137 IOUtils
.zip(zip
, "", src
, srcIsRoot
);
147 * Unzip the given ZIP file into the target directory.
151 * @param targetDirectory
152 * the target directory
154 * @return the number of extracted files (not directories)
156 * @throws IOException
157 * in case of I/O errors
159 public static long unzip(File zipFile
, File targetDirectory
)
163 if (targetDirectory
.exists() && targetDirectory
.isFile()) {
164 throw new IOException("Cannot unzip " + zipFile
+ " into "
165 + targetDirectory
+ ": it is not a directory");
168 targetDirectory
.mkdir();
169 if (!targetDirectory
.exists()) {
170 throw new IOException("Cannot create target directory "
174 FileInputStream in
= new FileInputStream(zipFile
);
176 ZipInputStream zipStream
= new ZipInputStream(in
);
178 for (ZipEntry entry
= zipStream
.getNextEntry(); entry
!= null; entry
= zipStream
180 File file
= new File(targetDirectory
, entry
.getName());
181 if (entry
.isDirectory()) {
184 IOUtils
.write(zipStream
, file
);
199 * Write the {@link String} content to {@link File}.
202 * the directory where to write the {@link File}
204 * the {@link File} name
208 * @throws IOException
209 * in case of I/O error
211 public static void writeSmallFile(File dir
, String filename
, String content
)
217 writeSmallFile(new File(dir
, filename
), content
);
221 * Write the {@link String} content to {@link File}.
224 * the {@link File} to write
228 * @throws IOException
229 * in case of I/O error
231 public static void writeSmallFile(File file
, String content
)
233 FileOutputStream out
= new FileOutputStream(file
);
235 out
.write(StringUtils
.getBytes(content
));
242 * Read the whole {@link File} content into a {@link String}.
247 * @return the content
249 * @throws IOException
250 * in case of I/O error
252 public static String
readSmallFile(File file
) throws IOException
{
253 InputStream stream
= new FileInputStream(file
);
255 return readSmallStream(stream
);
262 * Read the whole {@link InputStream} content into a {@link String}.
265 * the {@link InputStream}
267 * @return the content
269 * @throws IOException
270 * in case of I/O error
272 public static String
readSmallStream(InputStream stream
) throws IOException
{
273 ByteArrayOutputStream out
= new ByteArrayOutputStream();
276 return out
.toString("UTF-8");
283 * Recursively delete the given {@link File}, which may of course also be a
286 * Will either silently continue or throw an exception in case of error,
287 * depending upon the parameters.
290 * the target to delete
292 * TRUE to throw an {@link IOException} in case of error, FALSE
293 * to silently continue
295 * @return TRUE if all files were deleted, FALSE if an error occurred
297 * @throws IOException
298 * if an error occurred and the parameters allow an exception to
301 public static boolean deltree(File target
, boolean exception
)
303 List
<File
> list
= deltree(target
, null);
304 if (exception
&& !list
.isEmpty()) {
305 StringBuilder slist
= new StringBuilder();
306 for (File file
: list
) {
307 slist
.append("\n").append(file
.getPath());
310 throw new IOException("Cannot delete all the files from: <" //
311 + target
+ ">:" + slist
.toString());
314 return list
.isEmpty();
318 * Recursively delete the given {@link File}, which may of course also be a
321 * Will silently continue in case of error.
324 * the target to delete
326 * @return TRUE if all files were deleted, FALSE if an error occurred
328 public static boolean deltree(File target
) {
329 return deltree(target
, null).isEmpty();
333 * Recursively delete the given {@link File}, which may of course also be a
336 * Will collect all {@link File} that cannot be deleted in the given
340 * the target to delete
342 * the accumulator to use for errors, or NULL to create a new one
344 * @return the errors accumulator
346 public static List
<File
> deltree(File target
, List
<File
> errorAcc
) {
347 if (errorAcc
== null) {
348 errorAcc
= new ArrayList
<File
>();
351 File
[] files
= target
.listFiles();
353 for (File file
: files
) {
354 errorAcc
= deltree(file
, errorAcc
);
358 if (!target
.delete()) {
359 errorAcc
.add(target
);
366 * Open the given /-separated resource (from the binary root).
371 * @return the opened resource if found, NLL if not
373 public static InputStream
openResource(String name
) {
374 ClassLoader loader
= IOUtils
.class.getClassLoader();
375 if (loader
== null) {
376 loader
= ClassLoader
.getSystemClassLoader();
379 return loader
.getResourceAsStream(name
);
383 * Return a resetable {@link InputStream} from this stream, and reset it.
387 * @return the resetable stream, which <b>may</b> be the same
389 * @throws IOException
390 * in case of I/O error
392 public static InputStream
forceResetableStream(InputStream in
)
394 boolean resetable
= in
.markSupported();
398 } catch (IOException e
) {
407 final File tmp
= File
.createTempFile(".tmp-stream.", ".tmp");
412 return new MarkableFileInputStream(tmp
) {
414 public void close() throws IOException
{
422 } catch (IOException e
) {
429 * Convert the {@link InputStream} into a byte array.
436 * @throws IOException
437 * in case of I/O error
439 public static byte[] toByteArray(InputStream in
) throws IOException
{
440 ByteArrayOutputStream out
= new ByteArrayOutputStream();
443 return out
.toByteArray();
450 * Convert the {@link File} into a byte array.
453 * the input {@link File}
457 * @throws IOException
458 * in case of I/O error
460 public static byte[] toByteArray(File file
) throws IOException
{
461 FileInputStream fis
= new FileInputStream(file
);
463 return toByteArray(fis
);