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