1 package com.atlassian.user.util;
2
3 import org.apache.log4j.Logger;
4
5 import java.io.*;
6
7 /*
8 * Atlassian Source Code Template.
9 * User: anton
10 * Date: 15/08/2003
11 * Time: 11:38:41
12 * CVS Revision: $Revision: 2774 $
13 * Last CVS Commit: $Date: 2006-01-12 22:12:04 -0600 (Thu, 12 Jan 2006) $
14 * Author of last CVS Commit: $Author: nfaiz $
15 */
16
17 public class FileUtils
18 {
19 private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
20 private static final Logger log = Logger.getLogger(FileUtils.class);
21
22 /**
23 * Copy file from source to destination. The directories up to <code>destination</code> will be
24 * created if they don't already exist. <code>destination</code> will be overwritten if it
25 * already exists.
26 *
27 * @param source An existing non-directory <code>File</code> to copy bytes from.
28 * @param destination A non-directory <code>File</code> to write bytes to (possibly
29 * overwriting).
30 * @throws java.io.IOException if <code>source</code> does not exist, <code>destination</code> cannot be
31 * written to, or an IO error occurs during copying.
32 */
33 public static void copyFile(final File source, final File destination)
34 throws IOException
35 {
36 //check source exists
37 if (!source.exists())
38 {
39 final String message = "File " + source + " does not exist";
40 throw new IOException(message);
41 }
42
43 //does destinations directory exist ?
44 if (destination.getParentFile() != null &&
45 !destination.getParentFile().exists())
46 {
47 destination.getParentFile().mkdirs();
48 }
49
50 //make sure we can write to destination
51 if (destination.exists() && !destination.canWrite())
52 {
53 final String message = "Unable to open file " +
54 destination + " for writing.";
55 throw new IOException(message);
56 }
57
58 final FileInputStream input = new FileInputStream(source);
59 final FileOutputStream output = new FileOutputStream(destination);
60 copy(input, output);
61 shutdownStream(input);
62 shutdownStream(output);
63
64 if (source.length() != destination.length())
65 {
66 final String message = "Failed to copy full contents from " + source +
67 " to " + destination;
68 throw new IOException(message);
69 }
70 }
71
72 /**
73 * Copy bytes from an <code>InputStream</code> to an <code>OutputStream</code>.
74 *
75 * @param input the <code>InputStream</code> to read from
76 * @param output the <code>OutputStream</code> to write to
77 * @return the number of bytes copied
78 * @throws IOException In case of an I/O problem
79 */
80 public static int copy(final InputStream input, final OutputStream output)
81 throws IOException
82 {
83 return copy(input, output, DEFAULT_BUFFER_SIZE);
84 }
85
86 /**
87 * Copy bytes from an <code>InputStream</code> to an <code>OutputStream</code>.
88 *
89 * @param input the <code>InputStream</code> to read from
90 * @param output the <code>OutputStream</code> to write to
91 * @param bufferSize Size of internal buffer to use.
92 * @return the number of bytes copied
93 * @throws IOException In case of an I/O problem
94 */
95 public static int copy(final InputStream input,
96 final OutputStream output,
97 final int bufferSize)
98 throws IOException
99 {
100 final byte[] buffer = new byte[bufferSize];
101 int count = 0;
102 int n = 0;
103 while (-1 != (n = input.read(buffer)))
104 {
105 output.write(buffer, 0, n);
106 count += n;
107 }
108 return count;
109 }
110
111 /**
112 * Unconditionally close an <code>OutputStream</code>.
113 * Equivalent to {@link OutputStream#close()}, except any exceptions will be ignored.
114 *
115 * @param output A (possibly null) OutputStream
116 */
117 public static void shutdownStream(final OutputStream output)
118 {
119 if (output == null)
120 {
121 return;
122 }
123
124 try
125 {
126 output.close();
127 }
128 catch (final IOException ioe)
129 {
130 }
131 }
132
133 /**
134 * Unconditionally close an <code>InputStream</code>.
135 * Equivalent to {@link InputStream#close()}, except any exceptions will be ignored.
136 *
137 * @param input A (possibly null) InputStream
138 */
139 public static void shutdownStream(final InputStream input)
140 {
141 if (input == null)
142 {
143 return;
144 }
145
146 try
147 {
148 input.close();
149 }
150 catch (final IOException ioe)
151 {
152 }
153 }
154
155
156 /**
157 * safely performs a recursive delete on a directory
158 *
159 * @param dir
160 * @return
161 */
162 public static boolean deleteDir(File dir)
163 {
164 if (dir == null)
165 {
166 return false;
167 }
168
169 // to see if this directory is actually a symbolic link to a directory,
170 // we want to get its canonical path - that is, we follow the link to
171 // the file it's actually linked to
172 File candir;
173 try
174 {
175 candir = dir.getCanonicalFile();
176 }
177 catch (IOException e)
178 {
179 return false;
180 }
181
182 // a symbolic link has a different canonical path than its actual path,
183 // unless it's a link to itself
184 if (!candir.equals(dir.getAbsoluteFile()))
185 {
186 // this file is a symbolic link, and there's no reason for us to
187 // follow it, because then we might be deleting something outside of
188 // the directory we were told to delete
189 return false;
190 }
191
192 // now we go through all of the files and subdirectories in the
193 // directory and delete them one by one
194 File[] files = candir.listFiles();
195 if (files != null)
196 {
197 for (int i = 0; i < files.length; i++)
198 {
199 File file = files[i];
200
201 // in case this directory is actually a symbolic link, or it's
202 // empty, we want to try to delete the link before we try
203 // anything
204 boolean deleted = !file.delete();
205 if (deleted)
206 {
207 // deleting the file failed, so maybe it's a non-empty
208 // directory
209 if (file.isDirectory()) deleteDir(file);
210
211 // otherwise, there's nothing else we can do
212 }
213 }
214 }
215
216 // now that we tried to clear the directory out, we can try to delete it
217 // again
218 return dir.delete();
219 }
220
221 public static void deleteFilesBeginningWith(String directory, String prefix)
222 {
223 File dir = new File(directory);
224
225 if (!dir.isDirectory())
226 throw new IllegalArgumentException("directory arg. is not a dir. [" + directory + "]");
227
228 File[] files = dir.listFiles();
229
230 for (int i = 0; i < files.length; i++)
231 {
232 File file = files[i];
233 if (file.getName().startsWith(prefix))
234 {
235 if (!file.delete())
236 throw new RuntimeException("Could not delete " + file.getName());
237 }
238 }
239 }
240
241 /**
242 * creates a temp file with a given filename from an input stream in the classpath or a file in the filesystem
243 *
244 * @param fileName
245 * @return
246 * @throws IOException
247 */
248 public static File copyIntoTemporaryFile(String source, String fileName) throws IOException, Exception
249 {
250 File temp = File.createTempFile(fileName, null);
251 temp.deleteOnExit();
252
253 // Write content to the tempfile
254 BufferedWriter out = new BufferedWriter(new FileWriter(temp));
255 out.write(source);
256 out.close();
257
258 return temp;
259 }
260
261 public static String getInputStreamTextContent(InputStream is)
262 {
263 if (is == null)
264 {
265 return null;
266 }
267
268 String result = null;
269
270 try
271 {
272 ByteArrayOutputStream baos = new ByteArrayOutputStream(is.available());
273
274 pump(is, baos);
275
276 result = new String(baos.toByteArray());
277
278 is.close();
279 }
280 catch (IOException e)
281 {
282 log.error("IOException reading stream: " + e, e);
283 }
284
285 return result;
286 }
287
288
289 private static void pump(InputStream is, OutputStream os) throws IOException
290 {
291 byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
292 int lengthRead;
293
294 while ((lengthRead = is.read(buffer)) >= 0)
295 {
296 os.write(buffer, 0, lengthRead);
297 }
298 }
299 }