Coverage Report - org.jtheque.utils.io.FileUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
FileUtils
68%
177/257
51%
53/102
3.222
 
 1  
 package org.jtheque.utils.io;
 2  
 
 3  
 /*
 4  
  * This file is part of JTheque.
 5  
  *
 6  
  * JTheque is free software: you can redistribute it and/or modify
 7  
  * it under the terms of the GNU General Public License as published by
 8  
  * the Free Software Foundation, either version 3 of the License.
 9  
  *
 10  
  * JTheque is distributed in the hope that it will be useful,
 11  
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13  
  * GNU General Public License for more details.
 14  
  *
 15  
  * You should have received a copy of the GNU General Public License
 16  
  * along with JTheque.  If not, see <http://www.gnu.org/licenses/>.
 17  
  */
 18  
 
 19  
 import org.jtheque.utils.StringUtils;
 20  
 import org.slf4j.LoggerFactory;
 21  
 
 22  
 import java.io.BufferedInputStream;
 23  
 import java.io.BufferedOutputStream;
 24  
 import java.io.Closeable;
 25  
 import java.io.File;
 26  
 import java.io.FileFilter;
 27  
 import java.io.FileInputStream;
 28  
 import java.io.FileNotFoundException;
 29  
 import java.io.FileOutputStream;
 30  
 import java.io.IOException;
 31  
 import java.io.InputStream;
 32  
 import java.net.MalformedURLException;
 33  
 import java.net.URL;
 34  
 import java.net.URLConnection;
 35  
 import java.nio.channels.FileChannel;
 36  
 import java.security.MessageDigest;
 37  
 import java.security.NoSuchAlgorithmException;
 38  
 import java.util.ArrayList;
 39  
 import java.util.Collection;
 40  
 import java.util.Collections;
 41  
 import java.util.Date;
 42  
 import java.util.HashSet;
 43  
 import java.util.Scanner;
 44  
 import java.util.zip.ZipEntry;
 45  
 import java.util.zip.ZipFile;
 46  
 import java.util.zip.ZipInputStream;
 47  
 import java.util.zip.ZipOutputStream;
 48  
 
 49  
 /**
 50  
  * An utility class for file manipulation.
 51  
  *
 52  
  * @author Baptiste Wicht
 53  
  */
 54  
 public final class FileUtils {
 55  
     /**
 56  
      * The default size of buffer.
 57  
      */
 58  
     private static final int BUFFER_SIZE = 2048;
 59  
 
 60  
     /**
 61  
      * Construct a new FileUtils. This constructor is private because all methods are static.
 62  
      */
 63  
     private FileUtils() {
 64  0
         super();
 65  0
     }
 66  
 
 67  
     /**
 68  
      * Create the file if not exists.
 69  
      *
 70  
      * @param file The file to create.
 71  
      */
 72  
     public static void createIfNotExists(File file) {
 73  2
         if (!file.exists()) {
 74  0
             boolean created = file.mkdirs();
 75  
 
 76  0
             if (!created) {
 77  0
                 LoggerFactory.getLogger(FileUtils.class).debug("The folder (" + file.getAbsolutePath() + ") can not be created. ");
 78  
             }
 79  
         }
 80  2
     }
 81  
 
 82  
     /**
 83  
      * Return the text of the file.
 84  
      *
 85  
      * @param path The path to the file.
 86  
      * @return The content of the file
 87  
      */
 88  
     public static String getTextOfSystemResource(String path) {
 89  0
         InputStream stream = ClassLoader.getSystemResourceAsStream(path);
 90  
 
 91  0
         return getContentOfStream(stream);
 92  
     }
 93  
 
 94  
     /**
 95  
      * Return the text of the file referenced by the specified path.
 96  
      *
 97  
      * @param path The path to the file.
 98  
      * @return The text of the path.
 99  
      */
 100  
     public static String getTextOf(String path) {
 101  
         try {
 102  2
             InputStream stream = new FileInputStream(new File(path));
 103  
 
 104  2
             return getContentOfStream(stream);
 105  0
         } catch (FileNotFoundException e) {
 106  0
             LoggerFactory.getLogger(FileUtils.class).error("Unable to get the text of " + path, e);
 107  
         }
 108  
 
 109  0
         return null;
 110  
     }
 111  
 
 112  
     /**
 113  
      * Return the content of the stream.
 114  
      *
 115  
      * @param stream The stream to read from.
 116  
      * @return all the content of the stream in a <code>String</code> object.
 117  
      */
 118  
     private static String getContentOfStream(InputStream stream) {
 119  2
         StringBuilder content = new StringBuilder(1000);
 120  
 
 121  2
         Collection<String> lines = getLinesOf(stream);
 122  
 
 123  2
         boolean first = true;
 124  
 
 125  2
         for (String line : lines) {
 126  4
             if (first) {
 127  2
                 first = false;
 128  
             } else {
 129  2
                 content.append('\n');
 130  
             }
 131  
 
 132  4
             content.append(line);
 133  
         }
 134  
 
 135  2
         return content.toString();
 136  
     }
 137  
 
 138  
     /**
 139  
      * Return the lines of a stream.
 140  
      *
 141  
      * @param stream The stream to count the lines from.
 142  
      * @return The lines of the stream.
 143  
      */
 144  
     public static Collection<String> getLinesOf(InputStream stream) {
 145  4
         Collection<String> lines = new ArrayList<String>(100);
 146  
 
 147  4
         Scanner scanner = null;
 148  
         try {
 149  4
             scanner = new Scanner(new BufferedInputStream(stream));
 150  
 
 151  12
             while (scanner.hasNextLine()) {
 152  8
                 lines.add(scanner.nextLine());
 153  
             }
 154  
         } finally {
 155  4
             if (scanner != null) {
 156  4
                 scanner.close();
 157  
             }
 158  
         }
 159  
 
 160  4
         return lines;
 161  
     }
 162  
 
 163  
     /**
 164  
      * Download a file.
 165  
      *
 166  
      * @param filePath    The path to the file to download.
 167  
      * @param destination The path to the destination's file.
 168  
      * @throws FileException If an error occurs during the downloading process
 169  
      */
 170  
     public static void downloadFile(String filePath, String destination) throws FileException {
 171  2
         InputStream is = null;
 172  
         
 173  
         try {
 174  2
             URL url = new URL(filePath);
 175  
 
 176  2
             URLConnection connection = url.openConnection();
 177  
 
 178  2
             int length = connection.getContentLength();
 179  
 
 180  2
             if (length == -1) {
 181  0
                 throw new IOException("Empty file (" + filePath + ')');
 182  
             }
 183  
 
 184  2
             is = new BufferedInputStream(connection.getInputStream());
 185  
 
 186  2
             byte[] data = downloadData(is, length);
 187  
 
 188  2
             writeData(destination, data);
 189  0
         } catch (MalformedURLException e) {
 190  0
             throw new FileException("Exception occurred during downloading", e);
 191  0
         } catch (IOException e) {
 192  0
             throw new FileException("Exception occurred during downloading", e);
 193  
         } finally {
 194  2
             close(is);
 195  2
         }
 196  2
     }
 197  
 
 198  
     /**
 199  
      * Download data from a stream and return the data as a byte array.
 200  
      *
 201  
      * @param is     The input stream.
 202  
      * @param length The length to read.
 203  
      * @return The data into a byte array.
 204  
      * @throws IOException If an IO problem occurs during the reading.
 205  
      */
 206  
     private static byte[] downloadData(InputStream is, int length) throws IOException {
 207  2
         byte[] data = new byte[length];
 208  
 
 209  2
         int offset = 0;
 210  
 
 211  4
         while (offset < length) {
 212  2
             int currentBit = is.read(data, offset, data.length - offset);
 213  
 
 214  2
             if (currentBit == -1) {
 215  0
                 break;
 216  
             }
 217  
 
 218  2
             offset += currentBit;
 219  2
         }
 220  
 
 221  2
         if (offset != length) {
 222  0
             throw new IOException("The file has not been fully read (Only " + offset + " of " + length + ')');
 223  
         }
 224  2
         return data;
 225  
     }
 226  
 
 227  
     /**
 228  
      * Write data to a file.
 229  
      *
 230  
      * @param destination The destination file path.
 231  
      * @param data        The data to write.
 232  
      * @throws IOException If an IO problem occurs during the writing.
 233  
      */
 234  
     private static void writeData(String destination, byte[] data) throws IOException {
 235  2
         FileOutputStream destinationFile = null;
 236  
         try {
 237  2
             destinationFile = new FileOutputStream(destination);
 238  
 
 239  2
             destinationFile.write(data);
 240  
 
 241  2
             destinationFile.flush();
 242  
         } finally {
 243  2
             close(destinationFile);
 244  2
         }
 245  2
     }
 246  
 
 247  
     /**
 248  
      * Copy a file.
 249  
      *
 250  
      * @param sourcePath The path of the source.
 251  
      * @param targetPath The path of the destination.
 252  
      * @throws CopyException Thrown if an error occurs during the copy.
 253  
      */
 254  
     public static void copy(String sourcePath, String targetPath) throws CopyException {
 255  6
         File source = new File(sourcePath);
 256  6
         File target = new File(targetPath);
 257  
 
 258  6
         copy(source, target);
 259  4
     }
 260  
 
 261  
     /**
 262  
      * This method copy a source's file to a destination's file.
 263  
      *
 264  
      * @param source The source's file.
 265  
      * @param target The destination's file.
 266  
      * @throws CopyException Thrown when a problem occurs during the copy.
 267  
      */
 268  
     public static void copy(File source, File target) throws CopyException {
 269  20
         if (source.isDirectory()) {
 270  4
             copyDirectory(source, target);
 271  16
         } else if (source.exists()) {
 272  14
             FileChannel in = null;
 273  14
             FileChannel out = null;
 274  
 
 275  14
             FileInputStream inStream = null;
 276  14
             FileOutputStream outStream = null;
 277  
 
 278  
             try {
 279  14
                 inStream = new FileInputStream(source);
 280  14
                 outStream = new FileOutputStream(target);
 281  
 
 282  14
                 in = inStream.getChannel();
 283  14
                 out = outStream.getChannel();
 284  
 
 285  14
                 in.transferTo(0, in.size(), out);
 286  0
             } catch (IOException e) {
 287  0
                 throw new CopyException("Unable to copy the file", e);
 288  
             } finally {
 289  14
                 close(inStream);
 290  14
                 close(in);
 291  14
                 close(outStream);
 292  14
                 close(out);
 293  14
             }
 294  14
         } else {
 295  2
             throw new CopyException("File doesn't exist: " + source.getAbsolutePath());
 296  
         }
 297  18
     }
 298  
 
 299  
     /**
 300  
      * Copy a directory.
 301  
      *
 302  
      * @param source The source.
 303  
      * @param target The target.
 304  
      * @throws CopyException Thrown if an error occurs during the copying process.
 305  
      */
 306  
     private static void copyDirectory(File source, File target) throws CopyException {
 307  6
         if (!target.exists() && !target.mkdirs()) {
 308  0
             throw new CopyException("Impossible de créer le répertoire " + target.getAbsolutePath());
 309  
         }
 310  
 
 311  6
         File[] files = source.listFiles();
 312  
 
 313  16
         for (File sourceFile : files) {
 314  10
             if (sourceFile.isDirectory()) {
 315  2
                 copyDirectory(sourceFile, new File(source, sourceFile.getName()));
 316  
             }
 317  
 
 318  10
             String path = sourceFile.getAbsolutePath();
 319  10
             File targetFile = new File(target.getAbsolutePath() + path.substring(path.lastIndexOf(System.getProperty("file.separator"))));
 320  10
             copy(sourceFile, targetFile);
 321  
         }
 322  6
     }
 323  
 
 324  
     /**
 325  
      * Move a file.
 326  
      *
 327  
      * @param sourcePath The path of the source.
 328  
      * @param targetPath The path of the destination.
 329  
      * @throws CopyException Thrown if an error occurs during the move.
 330  
      */
 331  
     public static void move(String sourcePath, String targetPath) throws CopyException {
 332  4
         File source = new File(sourcePath);
 333  4
         File target = new File(targetPath);
 334  
 
 335  4
         copy(source, target);
 336  
 
 337  4
         delete(source);
 338  4
     }
 339  
 
 340  
     /**
 341  
      * Unzip a compressed file.
 342  
      *
 343  
      * @param source            The source buffer
 344  
      * @param destinationFolder The destination folder.
 345  
      * @return All the files of the zip
 346  
      */
 347  
     public static Collection<File> unzip(InputStream source, String destinationFolder) {
 348  2
         Collection<File> files = new ArrayList<File>(10);
 349  
 
 350  2
         ZipInputStream zis = new ZipInputStream(source);
 351  
 
 352  
         try {
 353  2
             ZipEntry entry = zis.getNextEntry();
 354  
 
 355  10
             while (entry != null) {
 356  8
                 File file = readFile(destinationFolder, zis, entry);
 357  
 
 358  8
                 files.add(file);
 359  
 
 360  8
                 entry = zis.getNextEntry();
 361  8
             }
 362  0
         } catch (FileNotFoundException e) {
 363  0
             LoggerFactory.getLogger(FileUtils.class).error("Exception occurred during unzipping " + e);
 364  0
         } catch (IOException e) {
 365  0
             LoggerFactory.getLogger(FileUtils.class).error("Exception occurred during unzipping " + e);
 366  
         } finally {
 367  2
             close(zis);
 368  2
         }
 369  
 
 370  2
         return files;
 371  
     }
 372  
 
 373  
     /**
 374  
      * Read an entry from the zip and unzip them into the specified destination folder.
 375  
      *
 376  
      * @param destinationFolder The folder to store the unzipped entry to.
 377  
      * @param zis               The zip input stream.
 378  
      * @param entry             The current entry.
 379  
      * @return The written file.
 380  
      * @throws IOException If an error occurs during the file processing.
 381  
      */
 382  
     private static File readFile(String destinationFolder, ZipInputStream zis, ZipEntry entry) throws IOException {
 383  8
         byte[] data = new byte[BUFFER_SIZE];
 384  
 
 385  8
         File file = new File(destinationFolder + '/' + entry.getName());
 386  
 
 387  8
         BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(file), BUFFER_SIZE);
 388  
 
 389  8
         int count = zis.read(data, 0, BUFFER_SIZE);
 390  
 
 391  16
         while (count != -1) {
 392  8
             outputStream.write(data, 0, count);
 393  
 
 394  8
             count = zis.read(data, 0, BUFFER_SIZE);
 395  
         }
 396  
 
 397  8
         close(outputStream);
 398  
 
 399  8
         return file;
 400  
     }
 401  
 
 402  
     /**
 403  
      * Zip files to a destination.
 404  
      *
 405  
      * @param files       The files we have to zip.
 406  
      * @param destination The archive destination file.
 407  
      */
 408  
     public static void zip(Iterable<File> files, File destination) {
 409  
         try {
 410  4
             zip(files, new BufferedOutputStream(new FileOutputStream(destination)));
 411  0
         } catch (FileNotFoundException e) {
 412  0
             LoggerFactory.getLogger(FileUtils.class).error("Exception occurred during zipping " + e);
 413  4
         }
 414  4
     }
 415  
 
 416  
     /**
 417  
      * Zip files to a destination stream.
 418  
      *
 419  
      * @param files  The files we have to zip.
 420  
      * @param buffer The destination stream.
 421  
      */
 422  
     public static void zip(Iterable<File> files, BufferedOutputStream buffer) {
 423  4
         ZipOutputStream zos = null;
 424  
         try {
 425  4
             zos = new ZipOutputStream(buffer);
 426  4
             zos.setMethod(ZipOutputStream.DEFLATED);
 427  4
             zos.setLevel(9);
 428  
 
 429  4
             zipFiles(files, zos);
 430  0
         } catch (Exception e) {
 431  0
             LoggerFactory.getLogger(FileUtils.class).error("Exception occurred during zipping " + e);
 432  
         } finally {
 433  4
             close(zos);
 434  4
         }
 435  4
     }
 436  
 
 437  
     /**
 438  
      * Zip a list of files into a zip output stream
 439  
      *
 440  
      * @param files The files to zip.
 441  
      * @param zos   The output stream to write in.
 442  
      * @throws IOException If an IO problem occurs during the zipping.
 443  
      */
 444  
     private static void zipFiles(Iterable<File> files, ZipOutputStream zos) throws IOException {
 445  4
         byte[] buf = new byte[BUFFER_SIZE];
 446  
 
 447  4
         for (File f : files) {
 448  16
             FileInputStream in = null;
 449  
             try {
 450  16
                 in = new FileInputStream(f);
 451  
 
 452  16
                 ZipEntry entry = new ZipEntry(f.getName());
 453  
 
 454  16
                 zos.putNextEntry(entry);
 455  
 
 456  16
                 int len = in.read(buf);
 457  32
                 while (len > 0) {
 458  16
                     zos.write(buf, 0, len);
 459  
 
 460  16
                     len = in.read(buf);
 461  
                 }
 462  
 
 463  16
                 zos.closeEntry();
 464  
             } finally {
 465  16
                 close(in);
 466  16
             }
 467  16
         }
 468  4
     }
 469  
 
 470  
     /**
 471  
      * Delete a file.
 472  
      *
 473  
      * @param path The path to the file.
 474  
      */
 475  
     public static void delete(String path) {
 476  8
         File file = new File(path);
 477  
 
 478  8
         delete(file);
 479  8
     }
 480  
 
 481  
     /**
 482  
      * Delete a file.
 483  
      *
 484  
      * @param file The file.
 485  
      */
 486  
     public static void delete(File file) {
 487  30
         if (!file.exists()) {
 488  2
             return;
 489  
         }
 490  
 
 491  28
         if (file.isDirectory()) {
 492  12
             for (File f : file.listFiles()) {
 493  8
                 delete(f.getAbsolutePath());
 494  
             }
 495  
         }
 496  
 
 497  28
         boolean deleted = file.delete();
 498  
 
 499  28
         if (!deleted) {
 500  0
             LoggerFactory.getLogger(FileUtils.class).debug("The file (" + file.getAbsolutePath() + ") can not be deleted. ");
 501  
         }
 502  28
     }
 503  
 
 504  
     /**
 505  
      * Create an empty file.
 506  
      *
 507  
      * @param path The path to the empty file.
 508  
      */
 509  
     public static void createEmptyFile(String path) {
 510  2
         File f = new File(path);
 511  
 
 512  2
         if (!f.exists()) {
 513  
             try {
 514  2
                 boolean created = f.createNewFile();
 515  
 
 516  2
                 if (!created) {
 517  0
                     LoggerFactory.getLogger(FileUtils.class).error("The file " + path + " cannot be created. ");
 518  
                 }
 519  0
             } catch (IOException e) {
 520  0
                 LoggerFactory.getLogger(FileUtils.class).error("Unable to create file " + e);
 521  2
             }
 522  
         }
 523  2
     }
 524  
 
 525  
     /**
 526  
      * Encrypt the string with the SHA-256 Algorithm.
 527  
      *
 528  
      * @param key The string to encrypt.
 529  
      * @return The encrypted key.
 530  
      */
 531  
     public static String encryptKey(String key) {
 532  4
         String encoded = "";
 533  4
         MessageDigest md = null;
 534  
 
 535  
         try {
 536  4
             md = MessageDigest.getInstance("SHA-256");
 537  
 
 538  4
             md.update(key.getBytes());
 539  
 
 540  4
             encoded = new String(md.digest());
 541  0
         } catch (NoSuchAlgorithmException e) {
 542  0
             LoggerFactory.getLogger(FileUtils.class).error("Unable to encrypt message " + e);
 543  
         } finally {
 544  4
             if (md != null) {
 545  4
                 md.reset();
 546  
             }
 547  
         }
 548  
 
 549  4
         return encoded;
 550  
     }
 551  
 
 552  
     /**
 553  
      * Test if a file is in a directory.
 554  
      *
 555  
      * @param file   The file to test.
 556  
      * @param folder The folder to test.
 557  
      * @return true if the file is in the directory.
 558  
      */
 559  
     public static boolean isFileInDirectory(File file, File folder) {
 560  6
         return file.getAbsolutePath().contains(folder.getAbsolutePath());
 561  
     }
 562  
 
 563  
     /**
 564  
      * Clear the folder. It seems delete all files tags starting with deleted and the file who the start tags refer
 565  
      * to.
 566  
      *
 567  
      * @param folder The folder to clean.
 568  
      */
 569  
     public static void clearFolder(File folder) {
 570  2
         Collection<File> toDelete = new HashSet<File>(10);
 571  
 
 572  14
         for (File f : folder.listFiles()) {
 573  12
             if (f.isFile() && f.getName().startsWith("deleted")) {
 574  6
                 File f2 = new File(f.getAbsolutePath().replace(f.getName(), f.getName().replace("deleted", "")));
 575  
 
 576  6
                 if (f2.exists()) {
 577  4
                     toDelete.add(f2);
 578  
                 }
 579  
 
 580  6
                 toDelete.add(f);
 581  
             }
 582  
         }
 583  
 
 584  2
         for (File f : toDelete) {
 585  10
             delete(f);
 586  
         }
 587  2
     }
 588  
 
 589  
     /**
 590  
      * Put the file into the directory.
 591  
      *
 592  
      * @param file   The file.
 593  
      * @param folder The folder.
 594  
      * @return true if the file is now in directory.
 595  
      */
 596  
     public static boolean putFileInDirectoryIfNot(File file, File folder) {
 597  2
         boolean correct = true;
 598  
 
 599  2
         if (!isFileInDirectory(file, folder)) {
 600  
             try {
 601  2
                 move(file.getAbsolutePath(), folder.getAbsolutePath() + '/' + file.getName());
 602  0
             } catch (CopyException e) {
 603  0
                 correct = false;
 604  2
             }
 605  
         }
 606  
 
 607  2
         return correct;
 608  
     }
 609  
 
 610  
     /**
 611  
      * Return an input stream to the path.
 612  
      *
 613  
      * @param path The path to get an input stream for.
 614  
      * @return An input stream to the file path.
 615  
      * @throws FileNotFoundException If the path doesn't represent an existing file.
 616  
      */
 617  
     public static InputStream asInputStream(String path) throws FileNotFoundException {
 618  0
         return new BufferedInputStream(new FileInputStream(path));
 619  
     }
 620  
 
 621  
     /**
 622  
      * Close a closable resource.
 623  
      *
 624  
      * @param closable The closable resource to close.
 625  
      */
 626  
     public static void close(Closeable closable) {
 627  90
         if (closable != null) {
 628  
             try {
 629  90
                 closable.close();
 630  0
             } catch (IOException e) {
 631  0
                 LoggerFactory.getLogger(FileUtils.class).error("Unable to close stream", e);
 632  90
             }
 633  
         }
 634  90
     }
 635  
 
 636  
     /**
 637  
      * Close a zip file.
 638  
      *
 639  
      * @param zipFile The zip file to close.
 640  
      */
 641  
     public static void close(ZipFile zipFile) {
 642  0
         if (zipFile != null) {
 643  
             try {
 644  0
                 zipFile.close();
 645  0
             } catch (IOException e) {
 646  0
                 LoggerFactory.getLogger(FileUtils.class).error("Unable to close zip file", e);
 647  0
             }
 648  
         }
 649  0
     }
 650  
 
 651  
     /**
 652  
      * Return an existing file.
 653  
      *
 654  
      * @return An existing file object.
 655  
      */
 656  
     public static File getAnExistingFile(){
 657  0
         for(File root : File.listRoots()){
 658  0
             for(File f : root.listFiles()){
 659  0
                 if(f.isFile() && f.length() > 0){
 660  0
                     return f;
 661  
                 }
 662  
             }
 663  
         }
 664  
 
 665  0
         return null;
 666  
     }
 667  
 
 668  
     /**
 669  
      * Return the size of the file specified by the path.
 670  
      *
 671  
      * @param path The path to the file.
 672  
      *
 673  
      * @return The size of the file or 0 if the file doesn't exist.
 674  
      */
 675  
     public static long getFileSize(String path){
 676  0
         if(StringUtils.isEmpty(path)){
 677  0
             return 0;
 678  
         }
 679  
 
 680  0
         return getFileSize(new File(path));
 681  
     }
 682  
 
 683  
     /**
 684  
      * Return the size of the specified file.
 685  
      *
 686  
      * @param file The file to calc the size.
 687  
      *
 688  
      * @return The size of the file or 0 if the file doesn't exist.
 689  
      */
 690  
     public static long getFileSize(File file){
 691  0
         if(file == null || !file.exists()){
 692  0
             return 0;
 693  
         }
 694  
 
 695  0
         return file.length();
 696  
     }
 697  
 
 698  
     /**
 699  
      * Return the date of the last modification of the file denoted by the specified path.
 700  
      *
 701  
      * @param path The path to the file.
 702  
      *
 703  
      * @return The date of the last modification of the file or null if the file doesn't not exists.
 704  
      */
 705  
     public static Date getLastModifiedDate(String path){
 706  0
         if(StringUtils.isEmpty(path)){
 707  0
             return null;
 708  
         }
 709  
 
 710  0
         return getLastModifiedDate(new File(path));
 711  
     }
 712  
 
 713  
     /**
 714  
      * Return the date of the last modification of the specified file. 
 715  
      *
 716  
      * @param file The file.
 717  
      *
 718  
      * @return The date of the last modification of the file or null if the file doesn't not exists.
 719  
      */
 720  
     public static Date getLastModifiedDate(File file){
 721  0
         if(file == null || !file.exists()){
 722  0
             return null;
 723  
         }
 724  
 
 725  0
         long lastModified = file.lastModified();
 726  
 
 727  0
         return lastModified == 0L ? null : new Date(lastModified);
 728  
     }
 729  
 
 730  
     /**
 731  
      * Return the next free name for the specified name in the specified folder.
 732  
      * If there is also a file named name in the specified folder, it will search for files
 733  
      * name[n].extension while it find a not existing file.
 734  
      *
 735  
      * @param folder The folder to search free name in.
 736  
      * @param name   The name to add.
 737  
      * @return The next free name for the specified name in the specified folder.
 738  
      */
 739  
     public static String getFreeName(String folder, String name) {
 740  0
         if (new File(folder, name).exists()) {
 741  0
             int count = 1;
 742  
 
 743  
             String freeName;
 744  
 
 745  
             do {
 746  0
                 freeName = name.substring(0, name.lastIndexOf('.')) + '[' + count + ']' + name.substring(name.lastIndexOf('.'));
 747  0
                 count++;
 748  0
             } while (new File(folder, freeName).exists());
 749  
 
 750  0
             return freeName;
 751  
         }
 752  
 
 753  0
         return name;
 754  
     }
 755  
 
 756  
     /**
 757  
      * Return all the files of the folder include the sub files and folders with no level limit.
 758  
      *
 759  
      * @param folder The folder to get the files from.
 760  
      * @param fileFilter The filter to use to select the files.
 761  
      *
 762  
      * @return A Collection containing all the files of the folder and his sub folders selected by the specified file filter.
 763  
      */
 764  
     public static Collection<File> getFilesOfFolder(File folder, FileFilter fileFilter) {
 765  0
         if(folder.isDirectory()){
 766  0
             Collection<File> files = new ArrayList<File>(50);
 767  
 
 768  0
             readFolder(folder, files, fileFilter);
 769  
 
 770  0
             return files;
 771  
         }
 772  
 
 773  0
         return Collections.emptyList();
 774  
     }
 775  
 
 776  
     /**
 777  
      * Read the folder and all the files of the folder in the collection.
 778  
      *
 779  
      * @param folder The folder to read.
 780  
      * @param files  The collection to add the files to.
 781  
      * @param fileFilter The filter to get the files with.
 782  
      */
 783  
     private static void readFolder(File folder, Collection<File> files, FileFilter fileFilter) {
 784  0
         for (File file : folder.listFiles(fileFilter)) {
 785  0
             if (file.isDirectory()) {
 786  0
                 readFolder(file, files, fileFilter);
 787  
             } else {
 788  0
                 files.add(file);
 789  
             }
 790  
         }
 791  0
     }
 792  
 }