1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.utils;
14 import java.io.BufferedReader;
15 import java.io.Closeable;
17 import java.io.FileFilter;
18 import java.io.FileInputStream;
19 import java.io.FileNotFoundException;
20 import java.io.FileOutputStream;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.io.InputStreamReader;
24 import java.io.OutputStream;
25 import java.io.RandomAccessFile;
26 import java.io.UnsupportedEncodingException;
29 import java.nio.channels.FileChannel;
30 import java.nio.charset.Charset;
31 import java.nio.charset.StandardCharsets;
32 import java.nio.file.FileVisitResult;
33 import java.nio.file.Files;
34 import java.nio.file.Path;
35 import java.nio.file.SimpleFileVisitor;
36 import java.nio.file.StandardCopyOption;
37 import java.nio.file.StandardOpenOption;
38 import java.nio.file.attribute.BasicFileAttributes;
39 import java.util.ArrayList;
40 import java.util.Arrays;
41 import java.util.Deque;
42 import java.util.LinkedList;
43 import java.util.Random;
44 import java.util.function.Predicate;
45 import java.util.zip.DataFormatException;
46 import java.util.zip.Deflater;
47 import java.util.zip.Inflater;
48 import java.util.zip.ZipEntry;
49 import java.util.zip.ZipException;
50 import java.util.zip.ZipInputStream;
51 import java.util.zip.ZipOutputStream;
53 import org.simantics.databoard.Bindings;
54 import org.simantics.databoard.adapter.AdaptException;
55 import org.simantics.databoard.adapter.Adapter;
56 import org.simantics.databoard.adapter.AdapterConstructionException;
57 import org.simantics.databoard.binding.Binding;
58 import org.simantics.databoard.type.Datatype;
59 import org.simantics.utils.bytes.LEInt;
60 import org.simantics.utils.strings.FileNameUtils;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
65 * Utilities for common file operations.
67 * see StreamUtil in databoard for Input/OutputStream reading/writing utils
68 * @see FileNameUtils for more utils
70 * @author Toni Kalajainen
71 * @author Tuukka Lehtonen
73 public class FileUtils {
75 private static final Logger LOGGER = LoggerFactory.getLogger(FileUtils.class);
78 * Create escaped filename
80 * @param name any string
81 * @return file compatible string
83 public static String escapeFileName(String name) {
85 return java.net.URLEncoder.encode(name, "UTF-8");
86 } catch (UnsupportedEncodingException e) {
88 throw new RuntimeException(e);
93 * Unescape filename into string
98 public static String unescapeFileName(String filename) {
100 return java.net.URLDecoder.decode(filename, "UTF-8");
101 } catch (UnsupportedEncodingException e) {
103 throw new RuntimeException(e);
107 public static File ensureParentDirectoryExists(String path) throws IOException {
108 return ensureParentDirectoryExists(new File(path));
112 * Ensures the parent directory pointed by the specified file path exists as a
115 * @param path the directory whose existence is to be ensured
116 * @return the requested directory
117 * @throws IOException if the specified directory cannot be created or
118 * already exists as a file
120 public static File ensureParentDirectoryExists(File path) throws IOException {
121 return ensureDirectoryExists(path.getParentFile());
125 public static File ensureDirectoryExists(String path) throws IOException {
126 return ensureDirectoryExists(new File(path));
130 * Ensures the directory pointed by the specified file path exists as a
133 * @param path the directory whose existence is to be ensured
134 * @return the requested directory
135 * @throws IOException if the specified directory cannot be created or
136 * already exists as a file
138 public static File ensureDirectoryExists(File path) throws IOException {
139 if (path.isDirectory())
140 // Already exists, everything OK.
144 // Path is not a directory but it exists, fail!
145 throw new IOException("file '" + path + "', already exists but it is not a directory");
149 // Path is not a directory but it exists, fail!
150 throw new IOException("could not create directory '" + path + "' for an unknown reason");
152 // Directory created OK.
157 * Copies the contents of a source file to the destination file.
159 * @param sourceFile the source file descriptor
160 * @param destFile the destination file descriptor
161 * @throws IOException when anything IO-related goes wrong during the copy
163 public static void copyFile(File sourceFile, File destFile) throws IOException {
164 if (!destFile.exists()) {
165 destFile.createNewFile();
168 FileInputStream fis = null;
169 FileOutputStream fos = null;
171 fis = new FileInputStream(sourceFile);
172 fos = new FileOutputStream(destFile);
173 FileChannel source = fis.getChannel();
174 FileChannel destination = fos.getChannel();
177 long size = source.size();
178 while (count < size) {
179 count += destination.transferFrom(source, count, size - count);
192 * Copy file or dir recursively.
196 * @throws IOException
198 public static void copy(File src, File dst) throws IOException
200 if (src.isDirectory()) {
201 if(!dst.exists()) dst.mkdir();
203 for (String file : src.list()) {
204 File srcFile = new File(src, file);
205 File dstFile = new File(dst, file);
206 copy(srcFile,dstFile);
214 // public static File createTempFileFromResource(URL sourceUrl) throws IOException {
215 // sourceUrl = FileLocator.resolve(sourceUrl);
218 // if (sourceUrl.getProtocol().equalsIgnoreCase("file"))
219 // sourceFile = new File(sourceUrl.getPath());
221 // sourceFile = new File(sourceUrl.toURI());
222 // } catch (URISyntaxException e) {
223 // throw new RuntimeException(e);
226 // File tempFile = File.createTempFile("tmp", ".tmp");
227 // FileUtils.copyFile(sourceFile, tempFile);
232 * Reads entire binary file
234 * @return contents of binary file
235 * @throws IOException on i/o problems
237 public static byte[] readFile(File file)
240 try (FileInputStream fis = new FileInputStream(file)) {
241 long size = file.length();
242 if (size>Integer.MAX_VALUE)
243 throw new IOException("File too big");
244 int len = (int) size;
245 byte data [] = new byte[len];
249 int read = fis.read(data, pos, len-pos);
257 * Creates and writes a binary file
260 * @throws IOException on i/o problems
262 public static void writeFile(File file, byte[] data)
265 // file.createNewFile();
266 // file.setWritable(true);
267 try (RandomAccessFile raf = new RandomAccessFile(file, "rw")) {
268 raf.setLength(data.length);
276 * Fetch the entire contents of the input stream text file, and return it in
277 * a String. This style of implementation does not throw Exceptions to the
280 * @param stream the stream to completely read in
282 public static String getContents(InputStream stream) throws IOException {
283 return getContents(stream, Charset.defaultCharset());
287 * Fetch the entire contents of the input stream text file, and return it in
288 * a String. This style of implementation does not throw Exceptions to the
291 * @param stream the stream to completely read in
293 public static String getContents(InputStream stream, Charset charset, String lineSeparator) throws IOException {
294 StringBuilder contents = new StringBuilder();
295 BufferedReader input = null;
297 input = new BufferedReader(new InputStreamReader(stream, charset));
300 while ((line = input.readLine()) != null) {
301 contents.append(line);
302 contents.append(lineSeparator);
307 // flush and close both "input" and its underlying
311 } catch (IOException ex) {
312 ex.printStackTrace();
315 return contents.toString();
318 public static String getContents(File f) throws IOException {
319 return getContents(f, Charset.defaultCharset());
322 public static String getContents(File f, Charset charset) throws IOException {
323 return getContents(new FileInputStream(f), charset);
326 public static String getContents(InputStream stream, Charset charset) throws IOException {
327 return getContents(stream, charset, System.getProperty("line.separator"));
330 public static String getContents(InputStream stream, String lineSeparator) throws IOException {
331 return getContents(stream, Charset.defaultCharset(), lineSeparator);
335 * Fetch the entire contents of a text file, and return it in a String. This
336 * style of implementation does not throw Exceptions to the caller.
338 * @param sourcePath is a file which already exists and can be read.
340 public static String getContents(String sourcePath) throws IOException {
341 return getContents(sourcePath, Charset.defaultCharset(), System.getProperty("line.separator"));
344 public static String getContents(String sourcePath, String lineSeparator) throws IOException {
345 return getContents(sourcePath, Charset.defaultCharset(), lineSeparator);
348 public static String getContents(String sourcePath, Charset charset) throws IOException {
349 return getContents(sourcePath, charset, System.getProperty("line.separator"));
353 * Fetch the entire contents of a text file, and return it in a String. This
354 * style of implementation does not throw Exceptions to the caller.
356 * @param sourcePath is a file which already exists and can be read.
358 public static String getContents(String sourcePath, Charset charset, String lineSeparator) throws IOException {
359 FileInputStream input = null;
361 input = new FileInputStream(sourcePath);
362 return getContents(input, charset, lineSeparator);
364 uncheckedClose(input);
369 * Get the contents of a file which is located inside a given bundle.
370 * This works regardless of whether the bundle is jarred or not.
372 * @param URL the resource to read in
373 * @return the contents of the resource
374 * @throws IOException if the file is not found or other io errors occur
376 public static String getContents(URL url) throws IOException {
378 throw new IllegalArgumentException("null URL");
379 InputStream input = null;
381 input = url.openStream();
382 return FileUtils.getContents(input);
384 uncheckedClose(input);
389 * Read a binary file into a java instance. Binary file is a variant,
390 * there is a filetype in the header of the file.
391 * If requested binding is not the exact binding of the file, an adapter is tried.
394 * @param binding content binding
396 * @throws IOException
398 public static Object readFile(InputStream stream, Binding binding) throws IOException {
399 Binding datatype_binding = Bindings.getBindingUnchecked( Datatype.class );
400 Datatype type = (Datatype) Bindings.getSerializerUnchecked( datatype_binding ).deserialize( stream );
402 if (type.equals(binding.type())) {
403 return Bindings.getSerializerUnchecked( binding ).deserialize(stream);
406 Binding fileContentBinding = Bindings.getMutableBinding(type);
407 Adapter adapter = Bindings.adapterFactory.getAdapter(fileContentBinding, binding, true, false);
408 Object value = Bindings.getSerializerUnchecked( fileContentBinding ).deserialize(stream);
409 return adapter.adapt( value );
410 } catch (AdapterConstructionException e) {
411 throw new IOException(e);
412 } catch (AdaptException e) {
413 throw new IOException(e);
419 * Deletes all files and sub-directories from the specified directory. If a
420 * file is specified, only that fill will be deleted.
423 * @throws IOException
425 public static void deleteAll(File dir) throws IOException {
431 if (dir.isDirectory()) {
432 File[] fs = dir.listFiles((FileFilter) null);
437 if (f.isDirectory()) {
441 throw new IOException("Could not delete file: " + f.getAbsolutePath());
447 throw new IOException("Could not delete directory: " + dir.getAbsolutePath());
449 } else if (dir.exists()) {
451 throw new IOException("Could not delete file: " + dir.getAbsolutePath());
457 * Deletes all files and sub-directories from the specified directory. If a
458 * file is specified, only that fill will be deleted.
460 * If the given directory contains files listed in the filter those files are not deleted
463 * directory from where to start the deletion
465 * filter containing specific file paths not to delete
466 * @throws IOException
468 public static void deleteAllWithFilter(File dir, ArrayList<String> filter) throws IOException {
470 if (!filter.contains(dir.getAbsolutePath())) {
476 if (dir.isDirectory()) {
477 File[] fs = dir.listFiles((FileFilter) null);
482 if (f.isDirectory()) {
483 deleteAllWithFilter(f, filter);
485 if (!filter.contains(f.getAbsolutePath())) {
487 throw new IOException("Could not delete file: " + f.getAbsolutePath());
492 if (!filter.contains(dir.getAbsolutePath())) {
494 throw new IOException("Could not delete directory: " + dir.getAbsolutePath());
497 } else if (dir.exists()) {
498 if (!filter.contains(dir.getAbsolutePath())) {
500 throw new IOException("Could not delete file: " + dir.getAbsolutePath());
506 public static ArrayList<String> createFileFilter(File dir, ArrayList<String> filter) {
508 filter = new ArrayList<String>();
510 filter.add(dir.getAbsolutePath());
514 if (dir.isDirectory()) {
515 File[] fs = dir.listFiles((FileFilter) null);
520 if (f.isDirectory()) {
521 createFileFilter(f, filter);
523 filter.add(f.getAbsolutePath());
526 filter.add(dir.getAbsolutePath());
527 } else if (dir.exists()) {
528 filter.add(dir.getAbsolutePath());
535 * Delete a directory incl. all files and sub-directories by best effort.
536 * Does not throw exceptions if deletion fails, simply tries to delete the
537 * provided directory to the best of Java File API's abilities.
540 * directory to delete recursively
541 * @boolean <code>true</code> if all files were successfully deleted,
542 * <code>false</code> if some or all failed to be deleted
544 public static boolean deleteDir(File dir) {
545 if (LOGGER.isDebugEnabled())
546 LOGGER.debug("Deleting directory "+dir);
547 boolean result = true;
549 if (!dir.isDirectory()) return false;
550 File[] fs = dir.listFiles();
553 if (f.isDirectory()) result &= deleteDir(f);
554 if (f.isFile()) result &= f.delete();
557 boolean ok = dir.delete();
558 // if (!ok) dir.deleteOnExit();
563 public static String deleteDirs(File dir) {
564 if (LOGGER.isDebugEnabled())
565 LOGGER.debug("Deleting directory "+dir);
566 boolean result = true;
568 if (!dir.isDirectory())
569 return dir + " is not a directory!";
570 File[] fs = dir.listFiles();
573 //System.out.println("file f :" + f);
574 if (f.isDirectory()) {
575 boolean a = deleteDir(f);
579 boolean a = f.delete();
585 boolean ok = dir.delete();
586 // if (!ok) dir.deleteOnExit();
588 return "deleteDirs succesful for " + dir + " : " + result;
592 * Closes a stream and ignores any resulting exception. This is useful
593 * when doing stream cleanup in a finally block where secondary exceptions
594 * are not worth logging.
596 public static void uncheckedClose(Closeable closeable) {
598 if (closeable != null)
600 } catch (IOException e) {
606 * Extracts the specified source file in the specified bundle into the
607 * specified local directory.
609 * @param url the source URL to stream the resource from
610 * @param targetFile the target file to write the resource to
611 * @param deleteOnExit <code>true</code> to use {@link File#deleteOnExit()}
612 * on the resulting file. Note that this does not guarantee that the
613 * file is deleted when the JVM exits
614 * @return the resulting file
615 * @throws FileNotFoundException
617 public static File copyResource(URL url, File targetFile, boolean deleteOnExit) throws IOException, FileNotFoundException {
619 throw new IllegalArgumentException("null url");
621 FileOutputStream os = null;
622 InputStream is = null;
624 if (targetFile.exists())
627 is = url.openStream();
629 byte [] buffer = new byte [16384];
630 os = new FileOutputStream (targetFile);
631 while ((read = is.read (buffer)) != -1) {
632 os.write(buffer, 0, read);
637 // Request removal of the extracted files on JVM exit.
639 targetFile.deleteOnExit();
642 FileUtils.uncheckedClose(os);
643 FileUtils.uncheckedClose(is);
648 * Creates the requested location under the system's temporary directories
649 * for temporary data storage.
651 * @param pathSegments the path segments that are appended to
652 * java.io.tmpdir. The path segments musn't contain path separators.
653 * @return the resulting temporary directory as a File object
654 * @throws IOException if anything goes wrong
656 public static File getOrCreateTemporaryDirectory(boolean requireEmptyDirectory, String... pathSegments) throws IOException {
657 String separator = System.getProperty("file.separator");
658 String tempDir = System.getProperty("java.io.tmpdir");
660 throw new IllegalStateException("'java.io.tmpdir' property is not defined, is the system TMP environment variable defined?");
662 if (!hasTrailingSeparator(tempDir))
663 tempDir = tempDir + separator;
665 for (int i = 0; i < pathSegments.length-1; ++i) {
666 if (containsSeparator(pathSegments[i]))
667 throw new IllegalArgumentException("path segments contain path separators: " + Arrays.toString(pathSegments));
668 tempDir = pathSegments[i] + separator;
671 // Find name for an empty or non-existing temporary directory
672 if (pathSegments.length > 0) {
673 String lastSegment = pathSegments[pathSegments.length - 1];
676 // This loop will not exit until it succeeds or some error occurs.
678 File temp = new File(tempDir + lastSegment + suffix);
680 if (!temp.exists()) {
681 // Found non-existent temporary directory!
683 // Ok, everything seems to be fine.
686 // For some reason the directory could not be created, lets
689 // Found an existing temporary file.
690 if (temp.isDirectory() && temp.canWrite()) {
691 if (requireEmptyDirectory) {
692 String[] files = temp.list();
694 if (files.length == 0) {
695 // Ok, the directory is empty and writable.
702 // Either the directory was empty or it could not be
703 // checked. In any case, don't use the directory.
707 // Try another directory name if no success with this one.
708 suffix = Integer.toHexString(counter);
712 return new File(tempDir);
715 private static boolean containsSeparator(String s) {
716 return s.contains("/") || s.contains("\\");
719 private static boolean hasTrailingSeparator(String s) {
720 return s.endsWith("/") || s.endsWith("\\");
724 * Very simple compression using ZLib
725 * @param input the uncompressed data
726 * @return the compressed data
728 public static byte[] deflate(byte[] input) {
729 // Compress the bytes
730 Deflater compresser = new Deflater(Deflater.BEST_COMPRESSION);
731 compresser.setInput(input);
734 int bufferSize = input.length<16 ? 16 : input.length;
735 byte buffer[] = new byte[bufferSize];
738 int compressedDataLength = compresser.deflate(buffer, bufferPos, buffer.length-bufferPos);
739 bufferPos += compressedDataLength;
740 if (!compresser.finished())
741 buffer = Arrays.copyOf(buffer, buffer.length + bufferSize);
742 } while (!compresser.finished());
744 byte[] result = new byte[bufferPos+4];
745 System.arraycopy(buffer, 0, result, 4, bufferPos);
746 byte sizeData[] = LEInt.toBytes(input.length);
747 System.arraycopy(sizeData, 0, result, 0, 4);
752 * Very simple decompression using ZLib.
753 * @param input the compressed input
754 * @return the uncompressed data
755 * @throws DataFormatException
757 public static byte[] inflate(byte[] input) throws DataFormatException {
758 // Decompress the bytes
759 int inflatedSize = LEInt.toInt(input);
760 Inflater decompresser = new Inflater();
761 decompresser.setInput(input, 4, input.length - 4);
762 byte[] result = new byte[inflatedSize];
763 int resultLength = decompresser.inflate(result);
764 assert(resultLength == inflatedSize);
770 public static boolean isValidFileName(String name) {
771 File f = new File(name) ;
774 boolean ok = f.createNewFile();
778 } catch (IOException ioe) {
786 * Create a temporary directory
788 * @return temporary directory
790 public static File createTmpDir()
792 String tmp = System.getenv("tmp");
793 if (tmp==null) tmp = "c:/temp";
794 Random r = new Random();
795 String randomName = "simantics-tmp-"+(r.nextInt(10000)+10000);
796 File tmpDir = new File(tmp+"/"+randomName);
797 tmpDir.deleteOnExit();
798 Boolean ok = tmpDir.mkdirs();
799 if (!ok) throw new RuntimeException("tmp dir "+tmpDir+" was not created");
803 public static void compressZip(String sourcePath, String zipDir) throws IOException {
804 if (LOGGER.isDebugEnabled())
805 LOGGER.debug("Compressing file " + sourcePath + " to zip " + zipDir + ".");
807 File filesource = new File(sourcePath);
808 URI base = filesource.toURI();
809 Deque<File> queue = new LinkedList<File>();
810 queue.push(filesource);
811 try (ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(zipDir))) {
812 while (!queue.isEmpty()) {
813 filesource = queue.pop();
814 for (File child : filesource.listFiles()) {
815 String name = base.relativize(child.toURI()).getPath();
816 if (child.isDirectory()) {
818 name = name.endsWith("/") ? name : name + "/";
819 zout.putNextEntry(new ZipEntry(name));
821 zout.putNextEntry(new ZipEntry(name));
828 LOGGER.debug("Filecompression done.");
832 public static void copy(File file, OutputStream out) throws IOException {
833 try (InputStream in = new FileInputStream(file)) {
839 * Extract a zip file into a directory
843 * @throws IOException
845 public static void extractZip(File zipFile, File dst) throws IOException {
846 if (LOGGER.isTraceEnabled())
847 LOGGER.trace("Extracting zip "+zipFile);
848 try (FileInputStream fis = new FileInputStream(zipFile)) {
849 extractZip(fis, dst);
853 public static void extractZip(File zipFile, File dst, Charset charset) throws IOException {
854 if (LOGGER.isTraceEnabled())
855 LOGGER.trace("Extracting zip "+zipFile);
856 try (FileInputStream fis = new FileInputStream(zipFile)) {
857 extractZip(fis, dst, charset);
861 * Extract a zip file into a directory
864 * @param dst directory
865 * @throws IOException
867 public static void extractZip(InputStream zipInput, File dst) throws IOException {
868 extractZip(zipInput, dst, StandardCharsets.UTF_8);
871 public static void extractZip(InputStream zipInput, File dst, Charset charset) throws IOException {
872 byte[] buf = new byte[8192];
873 ZipInputStream zis = new ZipInputStream(zipInput, charset);
876 entry = zis.getNextEntry();
877 while (entry != null) {
878 // for each entry to be extracted
879 String name = entry.getName();
880 if (LOGGER.isTraceEnabled())
881 LOGGER.trace("Extracting "+name);
882 File file = new File(dst, name);
884 if (entry.isDirectory())
886 if ( !file.exists() ) file.mkdirs();
888 File parent = file.getParentFile();
889 if (!parent.exists()) parent.mkdirs();
890 if (!file.exists()) file.createNewFile();
892 FileOutputStream fileoutputstream = new FileOutputStream(file);
895 while ((n = zis.read(buf, 0, buf.length)) > -1)
896 fileoutputstream.write(buf, 0, n);
897 } catch (ZipException e) {
898 throw new IOException("Failed to extract '" + name + "'.", e);
900 fileoutputstream.close();
905 entry = zis.getNextEntry();
911 // Test inflate & deflate
912 public static void main(String[] args) {
915 String str = "abcdefghijklmnopqrstuvwxyz";
916 byte data[] = str.getBytes();
917 System.out.println("Data:\t"+data.length);
918 byte deflated[] = deflate(data);
919 System.out.println("Deflated:\t"+deflated.length);
920 byte inflated[] = inflate(deflated);
921 System.out.println("Inflated:\t"+inflated.length);
922 String str2 = new String(inflated);
923 System.out.println("Strings are equal: "+str.endsWith(str2));
924 } catch (DataFormatException e) {
929 public static File[] listFilesByExtension(File directory, final String extension) {
930 return directory.listFiles(new ExtensionFilter(extension));
934 * Copy the content of the input stream into the output stream, using a temporary
935 * byte array buffer whose size is defined by {@link #IO_BUFFER_SIZE}.
937 * @param in The input stream to copy from.
938 * @param out The output stream to copy to.
940 * @throws IOException If any error occurs during the copy.
942 private static final int IO_BUFFER_SIZE = 64 * 1024;
944 public static void copy(InputStream in, OutputStream out) throws IOException {
945 byte[] b = new byte[IO_BUFFER_SIZE];
951 out.write(b, 0, read);
958 * @param maxBytesToCopy the maximum amount of bytes to copy
959 * @return the amount of bytes copied
960 * @throws IOException
962 public static long copy(InputStream in, OutputStream out, long maxBytesToCopy) throws IOException {
963 byte[] b = new byte[IO_BUFFER_SIZE];
965 while (read < maxBytesToCopy) {
966 int l = (int) Math.min((long) IO_BUFFER_SIZE, maxBytesToCopy-read);
967 int r = in.read(b, 0, l);
976 public static void deleteWithFilter(Path path, Predicate<Path> filter) throws IOException {
977 if (Files.exists(path))
978 Files.walkFileTree(path, new DeleteDirectoriesVisitor(filter));
981 public static void delete(Path path) throws IOException {
982 deleteWithFilter(path, null);
986 * Empties the specified directory but does not delete the directory itself.
987 * If a non-directory path is given, it is simply deleted.
990 * @throws IOException
992 public static void emptyDirectory(Path path) throws IOException {
993 if (Files.isDirectory(path))
994 Files.walkFileTree(path, new EmptyDirectoryVisitor());
996 Files.deleteIfExists(path);
999 public static void copy(Path from, Path to) throws IOException {
1000 Files.walkFileTree(from, new CopyDirectoriesVisitor(from, to));
1003 public static class DeleteDirectoriesVisitor extends SimpleFileVisitor<Path> {
1005 private Predicate<Path> filter;
1007 public DeleteDirectoriesVisitor(Predicate<Path> filter) {
1008 this.filter = filter;
1012 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
1013 if (filter != null && !filter.test(file)) {
1014 return FileVisitResult.CONTINUE;
1016 Files.deleteIfExists(file);
1017 return FileVisitResult.CONTINUE;
1021 public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
1024 if (filter != null && !filter.test(dir)) {
1025 return FileVisitResult.CONTINUE;
1027 Files.deleteIfExists(dir);
1028 return FileVisitResult.CONTINUE;
1032 private static class EmptyDirectoryVisitor extends SimpleFileVisitor<Path> {
1036 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
1037 Files.deleteIfExists(file);
1038 return FileVisitResult.CONTINUE;
1042 public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
1044 return FileVisitResult.CONTINUE;
1048 public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
1052 Files.deleteIfExists(dir);
1053 return FileVisitResult.CONTINUE;
1057 public static class CopyDirectoriesVisitor extends SimpleFileVisitor<Path> {
1059 private final Path fromPath;
1060 private final Path toPath;
1062 public CopyDirectoriesVisitor(Path fromPath, Path toPath) {
1063 this.fromPath = fromPath;
1064 this.toPath = toPath;
1068 public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
1069 Path targetPath = toPath.resolve(fromPath.relativize(dir));
1070 if(!Files.exists(targetPath)){
1071 Files.createDirectory(targetPath);
1073 return FileVisitResult.CONTINUE;
1077 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
1078 Files.copy(file, toPath.resolve(fromPath.relativize(file)), StandardCopyOption.REPLACE_EXISTING);
1079 return FileVisitResult.CONTINUE;
1083 public static void syncFile(File file) throws IOException {
1084 try (RandomAccessFile raf = new RandomAccessFile(file, "rw")) {
1089 public static void sync(Path path) throws IOException {
1090 try (InputStream stream = Files.newInputStream(path, StandardOpenOption.SYNC)) {