001    /*
002     * Created on Sep 23, 2006
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
005     * the License. You may obtain a copy of the License at
006     *
007     * http://www.apache.org/licenses/LICENSE-2.0
008     *
009     * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
010     * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
011     * specific language governing permissions and limitations under the License.
012     *
013     * Copyright @2006-2011 the original author or authors.
014     */
015    package org.fest.util;
016    
017    import static java.io.File.separator;
018    import static java.lang.String.*;
019    import static org.fest.util.Arrays.isEmpty;
020    import static org.fest.util.Closeables.close;
021    import static org.fest.util.Flushables.flush;
022    import static org.fest.util.Strings.*;
023    
024    import java.io.*;
025    import java.util.ArrayList;
026    import java.util.List;
027    
028    /**
029     * Utility methods related to files.
030     *
031     * @author Yvonne Wang
032     * @author Alex Ruiz
033     */
034    public class Files {
035    
036      /**
037       * Returns the names of the files inside the specified directory.
038       * @param dirName the name of the directory to start the search from.
039       * @param recurse if {@code true}, we will look in subdirectories.
040       * @return the names of the files inside the specified directory.
041       * @throws IllegalArgumentException if the given directory name does not point to an existing directory.
042       */
043      public static List<String> fileNamesIn(String dirName, boolean recurse) {
044        File dir = new File(dirName);
045        if (!dir.isDirectory()) throw new IllegalArgumentException(format("%s is not a directory", quote(dirName)));
046        return fileNamesIn(dir, recurse);
047      }
048    
049      /**
050       * Returns the names of the files inside the specified directory.
051       * @param dir the name of the directory to start the search from.
052       * @param recurse if {@code true}, we will look in subdirectories.
053       * @return the names of the files inside the specified directory.
054       */
055      private static List<String> fileNamesIn(File dir, boolean recurse) {
056        List<String> scriptNames = new ArrayList<String>();
057        File[] existingFiles = dir.listFiles();
058        if (isEmpty(existingFiles)) return scriptNames;
059        for (File existingFile : existingFiles) {
060          if (existingFile.isDirectory()) {
061            if (recurse) scriptNames.addAll(fileNamesIn(existingFile, recurse));
062            continue;
063          }
064          String filename = existingFile.getAbsolutePath();
065          if (!scriptNames.contains(filename)) scriptNames.add(filename);
066        }
067        return scriptNames;
068      }
069    
070      /**
071       * Returns the system's temporary directory.
072       * @return the system's temporary directory.
073       * @throws FilesException if this method cannot find or create the system's temporary directory.
074       */
075      public static File temporaryFolder() {
076        File temp = new File(temporaryFolderPath());
077        if (!temp.isDirectory()) throw new FilesException("Unable to find temporary directory");
078        return temp;
079      }
080    
081      /**
082       * Returns the path of the system's temporary directory. This method appends the system's file separator at the end of
083       * the path.
084       * @return the path of the system's temporary directory.
085       */
086      public static String temporaryFolderPath() {
087        return append(separator).to(System.getProperty("java.io.tmpdir"));
088      }
089    
090      /**
091       * Creates a new file in the system's temporary directory. The name of the file will be the result of:
092       * <pre>
093       * concat(String.valueOf(System.currentTimeMillis()), ".txt");
094       * </pre>
095       * @return the created file.
096       */
097      public static File newTemporaryFile() {
098        String tempFileName = concat(valueOf(System.currentTimeMillis()), ".txt");
099        return newFile(concat(temporaryFolderPath(), tempFileName));
100      }
101    
102      /**
103       * Creates a new directory in the system's temporary directory. The name of the directory will be the result of:
104       * <pre>
105       * System.currentTimeMillis();
106       * </pre>
107       * @return the created file.
108       */
109      public static File newTemporaryFolder() {
110        String tempFileName = String.valueOf(System.currentTimeMillis());
111        return newFolder(concat(temporaryFolderPath(), tempFileName));
112      }
113    
114      /**
115       * Creates a new file using the given path.
116       * @param path the path of the new file.
117       * @return the new created file.
118       * @throws FilesException if the path belongs to an existing non-empty directory.
119       * @throws FilesException if the path belongs to an existing file.
120       * @throws FilesException if any I/O error is thrown when creating the new file.
121       */
122      public static File newFile(String path) {
123        File file = new File(path);
124        if (file.isDirectory() && !isEmpty(file.list()))
125          throw cannotCreateNewFile(path, "a non-empty directory was found with the same path");
126        try {
127          if (!file.createNewFile()) throw cannotCreateNewFile(path, "a file was found with the same path");
128        } catch (IOException e) {
129          throw cannotCreateNewFile(path, e);
130        }
131        return file;
132      }
133    
134      /**
135       * Creates a new directory using the given path.
136       * @param path the path of the new directory.
137       * @return the new created directory.
138       * @throws FilesException if the path belongs to an existing non-empty directory.
139       * @throws FilesException if the path belongs to an existing file.
140       * @throws FilesException if any I/O error is thrown when creating the new directory.
141       */
142      public static File newFolder(String path) {
143        File file = new File(path);
144        if (file.isDirectory() && !isEmpty(file.list()))
145          throw cannotCreateNewFile(path, "a non-empty directory was found with the same path");
146        try {
147          if (!file.mkdir()) throw cannotCreateNewFile(path, "a file was found with the same path");
148        } catch (Exception e) {
149          throw cannotCreateNewFile(path, e);
150        }
151        return file;
152      }
153    
154      private static FilesException cannotCreateNewFile(String path, String reason) {
155        throw cannotCreateNewFile(path, reason, null);
156      }
157    
158      private static FilesException cannotCreateNewFile(String path, Exception cause) {
159        throw cannotCreateNewFile(path, null, cause);
160      }
161    
162      private static FilesException cannotCreateNewFile(String path, String reason, Exception cause) {
163        String message = String.format("Unable to create the new file %s", quote(path));
164        if (!Strings.isEmpty(reason)) message = concat(message, ": ", reason);
165        if (cause != null) throw new FilesException(message, cause);
166        throw new FilesException(message);
167      }
168    
169      /**
170       * Flushes and closes the given <code>{@link Writer}</code>. Any I/O errors catched by this method are ignored and not
171       * rethrown.
172       * @param writer the writer to flush and close.
173       */
174      public static void flushAndClose(Writer writer) {
175        if (writer == null) return;
176        flush(writer);
177        close(writer);
178      }
179    
180      /**
181       * Flushes and closes the given <code>{@link OutputStream}</code>. Any I/O errors catched by this method are ignored
182       * and not rethrown.
183       * @param out the output stream to flush and close.
184       */
185      public static void flushAndClose(OutputStream out) {
186        if (out == null) return;
187        flush(out);
188        close(out);
189      }
190    
191      /**
192       * Returns the current directory.
193       * @return the current directory.
194       * @throws FilesException if the current directory cannot be obtained.
195       */
196      public static File currentFolder() {
197        try {
198          return new File(".").getCanonicalFile();
199        } catch (IOException e) {
200          throw new FilesException("Unable to get current directory", e);
201        }
202      }
203    
204      /**
205       * Deletes the given file or directory.
206       * @param file the file or directory to delete.
207       */
208      public static void delete(File file) {
209        if (file.isFile()) {
210          file.delete();
211          return;
212        }
213        if (!file.isDirectory()) return;
214        for (File f : file.listFiles())
215          delete(f);
216        file.delete();
217      }
218    
219      private Files() {}
220    }