1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.transaction.util;
18
19 import java.io.File;
20 import java.io.FileInputStream;
21 import java.io.FileOutputStream;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.OutputStream;
25
26 /**
27 * Helper methods for file manipulation.
28 * All methods are <em>thread safe</em>.
29 *
30 * @version $Id: FileHelper.java 493628 2007-01-07 01:42:48Z joerg $
31 */
32 public final class FileHelper {
33
34 private static int BUF_SIZE = 50000;
35 private static byte[] BUF = new byte[BUF_SIZE];
36
37 /**
38 * Deletes a file specified by a path.
39 *
40 * @param path path of file to be deleted
41 * @return <code>true</code> if file has been deleted, <code>false</code> otherwise
42 */
43 public static boolean deleteFile(String path) {
44 File file = new File(path);
45 return file.delete();
46 }
47
48 /**
49 * Checks if a file specified by a path exits.
50 *
51 * @param path path of file to be checked
52 * @return <code>true</code> if file exists, <code>false</code> otherwise
53 */
54 public static boolean fileExists(String path) {
55 File file = new File(path);
56 return file.exists();
57 }
58
59 /**
60 * Creates a file specified by a path. All necessary directories will be created.
61 *
62 * @param path path of file to be created
63 * @return <code>true</code> if file has been created, <code>false</code> if the file already exists
64 * @throws IOException
65 * If an I/O error occurred
66 */
67 public static boolean createFile(String path) throws IOException {
68 File file = new File(path);
69 if (file.isDirectory()) {
70 return file.mkdirs();
71 } else {
72 File dir = file.getParentFile();
73 // do not check if this worked, as it may also return false, when all neccessary dirs are present
74 dir.mkdirs();
75 return file.createNewFile();
76 }
77 }
78
79 /**
80 * Removes a file. If the specified file is a directory all contained files will
81 * be removed recursively as well.
82 *
83 * @param toRemove file to be removed
84 */
85 public static void removeRec(File toRemove) {
86 if (toRemove.isDirectory()) {
87 File fileList[] = toRemove.listFiles();
88 for (int a = 0; a < fileList.length; a++) {
89 removeRec(fileList[a]);
90 }
91 }
92 toRemove.delete();
93 }
94
95 /**
96 * Moves one directory or file to another. Existing files will be replaced.
97 *
98 * @param source file to move from
99 * @param target file to move to
100 * @throws IOException if an I/O error occurs (may result in partially done work)
101 */
102 public static void moveRec(File source, File target) throws IOException {
103 byte[] sharedBuffer = new byte[BUF_SIZE];
104 moveRec(source, target, sharedBuffer);
105 }
106
107 static void moveRec(File source, File target, byte[] sharedBuffer) throws IOException {
108 if (source.isDirectory()) {
109 if (!target.exists()) {
110 target.mkdirs();
111 }
112 if (target.isDirectory()) {
113
114 File[] files = source.listFiles();
115 for (int i = 0; i < files.length; i++) {
116 File file = files[i];
117 File targetFile = new File(target, file.getName());
118 if (file.isFile()) {
119 if (targetFile.exists()) {
120 targetFile.delete();
121 }
122 if (!file.renameTo(targetFile)) {
123 copy(file, targetFile, sharedBuffer);
124 file.delete();
125 }
126 } else {
127 if (!targetFile.exists()) {
128 if (!targetFile.mkdirs()) {
129 throw new IOException("Could not create target directory: "
130 + targetFile);
131 }
132 }
133 moveRec(file, targetFile);
134 }
135 }
136 source.delete();
137 }
138 } else {
139 if (!target.isDirectory()) {
140 copy(source, target, sharedBuffer);
141 source.delete();
142 }
143 }
144 }
145
146 /**
147 * Copies one directory or file to another. Existing files will be replaced.
148 *
149 * @param source directory or file to copy from
150 * @param target directory or file to copy to
151 * @throws IOException if an I/O error occurs (may result in partially done work)
152 */
153 public static void copyRec(File source, File target) throws IOException {
154 byte[] sharedBuffer = new byte[BUF_SIZE];
155 copyRec(source, target, sharedBuffer);
156 }
157
158 static void copyRec(File source, File target, byte[] sharedBuffer) throws IOException {
159 if (source.isDirectory()) {
160 if (!target.exists()) {
161 target.mkdirs();
162 }
163 if (target.isDirectory()) {
164
165 File[] files = source.listFiles();
166 for (int i = 0; i < files.length; i++) {
167 File file = files[i];
168 File targetFile = new File(target, file.getName());
169 if (file.isFile()) {
170 if (targetFile.exists()) {
171 targetFile.delete();
172 }
173 copy(file, targetFile, sharedBuffer);
174 } else {
175 targetFile.mkdirs();
176 copyRec(file, targetFile);
177 }
178 }
179 }
180 } else {
181 if (!target.isDirectory()) {
182 if (!target.exists()) {
183 File dir = target.getParentFile();
184 if(!dir.exists() && !dir.mkdirs()) {
185 throw new IOException("Could not create target directory: " + dir);
186 }
187 if (!target.createNewFile()) {
188 throw new IOException("Could not create target file: " + target);
189 }
190 }
191 copy(source, target, sharedBuffer);
192 }
193 }
194 }
195
196 /**
197 * Copies one file to another using {@link #copy(InputStream, OutputStream)}.
198 *
199 * @param input
200 * source file
201 * @param output
202 * destination file
203 * @return the number of bytes copied
204 * @throws IOException
205 * if an I/O error occurs (may result in partially done work)
206 * @see #copy(InputStream, OutputStream)
207 */
208 public static long copy(File input, File output) throws IOException {
209 FileInputStream in = null;
210 try {
211 in = new FileInputStream(input);
212 return copy(in, output);
213 } finally {
214 if (in != null) {
215 try {
216 in.close();
217 } catch (IOException e) {
218 }
219 }
220 }
221 }
222
223 /**
224 * Copies one file to another using the supplied buffer.
225 *
226 * @param input source file
227 * @param output destination file
228 * @param copyBuffer buffer used for copying
229 * @return the number of bytes copied
230 * @throws IOException if an I/O error occurs (may result in partially done work)
231 * @see #copy(InputStream, OutputStream)
232 */
233 public static long copy(File input, File output, byte[] copyBuffer) throws IOException {
234 FileInputStream in = null;
235 FileOutputStream out = null;
236 try {
237 in = new FileInputStream(input);
238 out = new FileOutputStream(output);
239 return copy(in, out, copyBuffer);
240 } finally {
241 if (in != null) {
242 try {
243 in.close();
244 } catch (IOException e) {
245 }
246 }
247 if (out != null) {
248 try {
249 out.close();
250 } catch (IOException e) {
251 }
252 }
253 }
254 }
255
256 /**
257 * Copies an <code>InputStream</code> to a file using {@link #copy(InputStream, OutputStream)}.
258 *
259 * @param in stream to copy from
260 * @param outputFile file to copy to
261 * @return the number of bytes copied
262 * @throws IOException if an I/O error occurs (may result in partially done work)
263 * @see #copy(InputStream, OutputStream)
264 */
265 public static long copy(InputStream in, File outputFile) throws IOException {
266 FileOutputStream out = null;
267 try {
268 out = new FileOutputStream(outputFile);
269 return copy(in, out);
270 } finally {
271 if (out != null) {
272 try {
273 out.close();
274 } catch (IOException e) {
275 }
276 }
277 }
278 }
279
280 /**
281 * Copies an <code>InputStream</code> to an <code>OutputStream</code> using a local internal buffer for performance.
282 * Compared to {@link #globalBufferCopy(InputStream, OutputStream)} this method allows for better
283 * concurrency, but each time it is called generates a buffer which will be garbage.
284 *
285 * @param in stream to copy from
286 * @param out stream to copy to
287 * @return the number of bytes copied
288 * @throws IOException if an I/O error occurs (may result in partially done work)
289 * @see #globalBufferCopy(InputStream, OutputStream)
290 */
291 public static long copy(InputStream in, OutputStream out) throws IOException {
292 // we need a buffer of our own, so no one else interferes
293 byte[] buf = new byte[BUF_SIZE];
294 return copy(in, out, buf);
295 }
296
297 /**
298 * Copies an <code>InputStream</code> to an <code>OutputStream</code> using a global internal buffer for performance.
299 * Compared to {@link #copy(InputStream, OutputStream)} this method generated no garbage,
300 * but decreases concurrency.
301 *
302 * @param in stream to copy from
303 * @param out stream to copy to
304 * @return the number of bytes copied
305 * @throws IOException if an I/O error occurs (may result in partially done work)
306 * @see #copy(InputStream, OutputStream)
307 */
308 public static long globalBufferCopy(InputStream in, OutputStream out) throws IOException {
309 synchronized (BUF) {
310 return copy(in, out, BUF);
311 }
312 }
313
314 /**
315 * Copies an <code>InputStream</code> to an <code>OutputStream</code> using the specified buffer.
316 *
317 * @param in stream to copy from
318 * @param out stream to copy to
319 * @param copyBuffer buffer used for copying
320 * @return the number of bytes copied
321 * @throws IOException if an I/O error occurs (may result in partially done work)
322 * @see #globalBufferCopy(InputStream, OutputStream)
323 * @see #copy(InputStream, OutputStream)
324 */
325 public static long copy(InputStream in, OutputStream out, byte[] copyBuffer) throws IOException {
326 long bytesCopied = 0;
327 int read = -1;
328
329 while ((read = in.read(copyBuffer, 0, copyBuffer.length)) != -1) {
330 out.write(copyBuffer, 0, read);
331 bytesCopied += read;
332 }
333 return bytesCopied;
334 }
335 }