1 | /* |
2 | * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0, |
3 | * and the EPL 1.0 (http://h2database.com/html/license.html). |
4 | * Initial Developer: H2 Group |
5 | */ |
6 | package org.h2.store.fs; |
7 | |
8 | import java.io.EOFException; |
9 | import java.io.IOException; |
10 | import java.io.InputStream; |
11 | import java.io.OutputStream; |
12 | import java.nio.ByteBuffer; |
13 | import java.nio.channels.FileChannel; |
14 | import java.util.List; |
15 | import org.h2.util.New; |
16 | |
17 | /** |
18 | * This utility class contains utility functions that use the file system |
19 | * abstraction. |
20 | */ |
21 | public class FileUtils { |
22 | |
23 | /** |
24 | * Checks if a file exists. |
25 | * This method is similar to Java 7 <code>java.nio.file.Path.exists</code>. |
26 | * |
27 | * @param fileName the file name |
28 | * @return true if it exists |
29 | */ |
30 | public static boolean exists(String fileName) { |
31 | return FilePath.get(fileName).exists(); |
32 | } |
33 | |
34 | /** |
35 | * Create a directory (all required parent directories must already exist). |
36 | * This method is similar to Java 7 |
37 | * <code>java.nio.file.Path.createDirectory</code>. |
38 | * |
39 | * @param directoryName the directory name |
40 | */ |
41 | public static void createDirectory(String directoryName) { |
42 | FilePath.get(directoryName).createDirectory(); |
43 | } |
44 | |
45 | /** |
46 | * Create a new file. This method is similar to Java 7 |
47 | * <code>java.nio.file.Path.createFile</code>, but returns false instead of |
48 | * throwing a exception if the file already existed. |
49 | * |
50 | * @param fileName the file name |
51 | * @return true if creating was successful |
52 | */ |
53 | public static boolean createFile(String fileName) { |
54 | return FilePath.get(fileName).createFile(); |
55 | } |
56 | |
57 | /** |
58 | * Delete a file or directory if it exists. |
59 | * Directories may only be deleted if they are empty. |
60 | * This method is similar to Java 7 |
61 | * <code>java.nio.file.Path.deleteIfExists</code>. |
62 | * |
63 | * @param path the file or directory name |
64 | */ |
65 | public static void delete(String path) { |
66 | FilePath.get(path).delete(); |
67 | } |
68 | |
69 | /** |
70 | * Get the canonical file or directory name. This method is similar to Java |
71 | * 7 <code>java.nio.file.Path.toRealPath</code>. |
72 | * |
73 | * @param fileName the file name |
74 | * @return the normalized file name |
75 | */ |
76 | public static String toRealPath(String fileName) { |
77 | return FilePath.get(fileName).toRealPath().toString(); |
78 | } |
79 | |
80 | /** |
81 | * Get the parent directory of a file or directory. This method returns null |
82 | * if there is no parent. This method is similar to Java 7 |
83 | * <code>java.nio.file.Path.getParent</code>. |
84 | * |
85 | * @param fileName the file or directory name |
86 | * @return the parent directory name |
87 | */ |
88 | public static String getParent(String fileName) { |
89 | FilePath p = FilePath.get(fileName).getParent(); |
90 | return p == null ? null : p.toString(); |
91 | } |
92 | |
93 | /** |
94 | * Check if the file name includes a path. This method is similar to Java 7 |
95 | * <code>java.nio.file.Path.isAbsolute</code>. |
96 | * |
97 | * @param fileName the file name |
98 | * @return if the file name is absolute |
99 | */ |
100 | public static boolean isAbsolute(String fileName) { |
101 | return FilePath.get(fileName).isAbsolute(); |
102 | } |
103 | |
104 | /** |
105 | * Rename a file if this is allowed. This method is similar to Java 7 |
106 | * <code>java.nio.file.Files.move</code>. |
107 | * |
108 | * @param source the old fully qualified file name |
109 | * @param target the new fully qualified file name |
110 | */ |
111 | public static void move(String source, String target) { |
112 | FilePath.get(source).moveTo(FilePath.get(target), false); |
113 | } |
114 | |
115 | /** |
116 | * Rename a file if this is allowed, and try to atomically replace an |
117 | * existing file. This method is similar to Java 7 |
118 | * <code>java.nio.file.Files.move</code>. |
119 | * |
120 | * @param source the old fully qualified file name |
121 | * @param target the new fully qualified file name |
122 | */ |
123 | public static void moveAtomicReplace(String source, String target) { |
124 | FilePath.get(source).moveTo(FilePath.get(target), true); |
125 | } |
126 | |
127 | /** |
128 | * Get the file or directory name (the last element of the path). |
129 | * This method is similar to Java 7 <code>java.nio.file.Path.getName</code>. |
130 | * |
131 | * @param path the directory and file name |
132 | * @return just the file name |
133 | */ |
134 | public static String getName(String path) { |
135 | return FilePath.get(path).getName(); |
136 | } |
137 | |
138 | /** |
139 | * List the files and directories in the given directory. |
140 | * This method is similar to Java 7 |
141 | * <code>java.nio.file.Path.newDirectoryStream</code>. |
142 | * |
143 | * @param path the directory |
144 | * @return the list of fully qualified file names |
145 | */ |
146 | public static List<String> newDirectoryStream(String path) { |
147 | List<FilePath> list = FilePath.get(path).newDirectoryStream(); |
148 | int len = list.size(); |
149 | List<String> result = New.arrayList(len); |
150 | for (int i = 0; i < len; i++) { |
151 | result.add(list.get(i).toString()); |
152 | } |
153 | return result; |
154 | } |
155 | |
156 | /** |
157 | * Get the last modified date of a file. |
158 | * This method is similar to Java 7 |
159 | * <code>java.nio.file.attribute.Attributes. |
160 | * readBasicFileAttributes(file).lastModified().toMillis()</code> |
161 | * |
162 | * @param fileName the file name |
163 | * @return the last modified date |
164 | */ |
165 | public static long lastModified(String fileName) { |
166 | return FilePath.get(fileName).lastModified(); |
167 | } |
168 | |
169 | /** |
170 | * Get the size of a file in bytes |
171 | * This method is similar to Java 7 |
172 | * <code>java.nio.file.attribute.Attributes. |
173 | * readBasicFileAttributes(file).size()</code> |
174 | * |
175 | * @param fileName the file name |
176 | * @return the size in bytes |
177 | */ |
178 | public static long size(String fileName) { |
179 | return FilePath.get(fileName).size(); |
180 | } |
181 | |
182 | /** |
183 | * Check if it is a file or a directory. |
184 | * <code>java.nio.file.attribute.Attributes. |
185 | * readBasicFileAttributes(file).isDirectory()</code> |
186 | * |
187 | * @param fileName the file or directory name |
188 | * @return true if it is a directory |
189 | */ |
190 | public static boolean isDirectory(String fileName) { |
191 | return FilePath.get(fileName).isDirectory(); |
192 | } |
193 | |
194 | /** |
195 | * Open a random access file object. |
196 | * This method is similar to Java 7 |
197 | * <code>java.nio.channels.FileChannel.open</code>. |
198 | * |
199 | * @param fileName the file name |
200 | * @param mode the access mode. Supported are r, rw, rws, rwd |
201 | * @return the file object |
202 | */ |
203 | public static FileChannel open(String fileName, String mode) |
204 | throws IOException { |
205 | return FilePath.get(fileName).open(mode); |
206 | } |
207 | |
208 | /** |
209 | * Create an input stream to read from the file. |
210 | * This method is similar to Java 7 |
211 | * <code>java.nio.file.Path.newInputStream</code>. |
212 | * |
213 | * @param fileName the file name |
214 | * @return the input stream |
215 | */ |
216 | public static InputStream newInputStream(String fileName) |
217 | throws IOException { |
218 | return FilePath.get(fileName).newInputStream(); |
219 | } |
220 | |
221 | /** |
222 | * Create an output stream to write into the file. |
223 | * This method is similar to Java 7 |
224 | * <code>java.nio.file.Path.newOutputStream</code>. |
225 | * |
226 | * @param fileName the file name |
227 | * @param append if true, the file will grow, if false, the file will be |
228 | * truncated first |
229 | * @return the output stream |
230 | */ |
231 | public static OutputStream newOutputStream(String fileName, boolean append) |
232 | throws IOException { |
233 | return FilePath.get(fileName).newOutputStream(append); |
234 | } |
235 | |
236 | /** |
237 | * Check if the file is writable. |
238 | * This method is similar to Java 7 |
239 | * <code>java.nio.file.Path.checkAccess(AccessMode.WRITE)</code> |
240 | * |
241 | * @param fileName the file name |
242 | * @return if the file is writable |
243 | */ |
244 | public static boolean canWrite(String fileName) { |
245 | return FilePath.get(fileName).canWrite(); |
246 | } |
247 | |
248 | // special methods ======================================= |
249 | |
250 | /** |
251 | * Disable the ability to write. The file can still be deleted afterwards. |
252 | * |
253 | * @param fileName the file name |
254 | * @return true if the call was successful |
255 | */ |
256 | public static boolean setReadOnly(String fileName) { |
257 | return FilePath.get(fileName).setReadOnly(); |
258 | } |
259 | |
260 | /** |
261 | * Get the unwrapped file name (without wrapper prefixes if wrapping / |
262 | * delegating file systems are used). |
263 | * |
264 | * @param fileName the file name |
265 | * @return the unwrapped |
266 | */ |
267 | public static String unwrap(String fileName) { |
268 | return FilePath.get(fileName).unwrap().toString(); |
269 | } |
270 | |
271 | // utility methods ======================================= |
272 | |
273 | /** |
274 | * Delete a directory or file and all subdirectories and files. |
275 | * |
276 | * @param path the path |
277 | * @param tryOnly whether errors should be ignored |
278 | */ |
279 | public static void deleteRecursive(String path, boolean tryOnly) { |
280 | if (exists(path)) { |
281 | if (isDirectory(path)) { |
282 | for (String s : newDirectoryStream(path)) { |
283 | deleteRecursive(s, tryOnly); |
284 | } |
285 | } |
286 | if (tryOnly) { |
287 | tryDelete(path); |
288 | } else { |
289 | delete(path); |
290 | } |
291 | } |
292 | } |
293 | |
294 | /** |
295 | * Create the directory and all required parent directories. |
296 | * |
297 | * @param dir the directory name |
298 | */ |
299 | public static void createDirectories(String dir) { |
300 | if (dir != null) { |
301 | if (exists(dir)) { |
302 | if (!isDirectory(dir)) { |
303 | // this will fail |
304 | createDirectory(dir); |
305 | } |
306 | } else { |
307 | String parent = getParent(dir); |
308 | createDirectories(parent); |
309 | createDirectory(dir); |
310 | } |
311 | } |
312 | } |
313 | |
314 | /** |
315 | * Try to delete a file (ignore errors). |
316 | * |
317 | * @param fileName the file name |
318 | * @return true if it worked |
319 | */ |
320 | public static boolean tryDelete(String fileName) { |
321 | try { |
322 | FilePath.get(fileName).delete(); |
323 | return true; |
324 | } catch (Exception e) { |
325 | return false; |
326 | } |
327 | } |
328 | |
329 | /** |
330 | * Create a new temporary file. |
331 | * |
332 | * @param prefix the prefix of the file name (including directory name if |
333 | * required) |
334 | * @param suffix the suffix |
335 | * @param deleteOnExit if the file should be deleted when the virtual |
336 | * machine exists |
337 | * @param inTempDir if the file should be stored in the temporary directory |
338 | * @return the name of the created file |
339 | */ |
340 | public static String createTempFile(String prefix, String suffix, |
341 | boolean deleteOnExit, boolean inTempDir) throws IOException { |
342 | return FilePath.get(prefix).createTempFile( |
343 | suffix, deleteOnExit, inTempDir).toString(); |
344 | } |
345 | |
346 | /** |
347 | * Fully read from the file. This will read all remaining bytes, |
348 | * or throw an EOFException if not successful. |
349 | * |
350 | * @param channel the file channel |
351 | * @param dst the byte buffer |
352 | */ |
353 | public static void readFully(FileChannel channel, ByteBuffer dst) |
354 | throws IOException { |
355 | do { |
356 | int r = channel.read(dst); |
357 | if (r < 0) { |
358 | throw new EOFException(); |
359 | } |
360 | } while (dst.remaining() > 0); |
361 | } |
362 | |
363 | /** |
364 | * Fully write to the file. This will write all remaining bytes. |
365 | * |
366 | * @param channel the file channel |
367 | * @param src the byte buffer |
368 | */ |
369 | public static void writeFully(FileChannel channel, ByteBuffer src) |
370 | throws IOException { |
371 | do { |
372 | channel.write(src); |
373 | } while (src.remaining() > 0); |
374 | } |
375 | |
376 | } |