44

I see that Java 8 has significantly cleaned up reading the contents of a file into a String:

String contents = new String(Files.readAllBytes(Paths.get(new URI(someUrl))));

I am wondering if there is something similar (cleaner/less code/more concise) for copying directories recursively. In Java 7 land, it's still something like:

public void copyFolder(File src, File dest) throws IOException{
    if(src.isDirectory()){
        if(!dest.exists()){
            dest.mkdir();
        }

        String files[] = src.list();

        for (String file : files) {
            File srcFile = new File(src, file);
            File destFile = new File(dest, file);

            copyFolder(srcFile,destFile);
        }

    } else {
        InputStream in = new FileInputStream(src);
        OutputStream out = new FileOutputStream(dest); 

        byte[] buffer = new byte[1024];

        int length;
        while ((length = in.read(buffer)) > 0){
            out.write(buffer, 0, length);
        }

        in.close();
        out.close();
    }
}

Any improvements here in Java 8?

smeeb
  • 27,777
  • 57
  • 250
  • 447
  • 2
    FYI `Files.readAllBytes(Paths.get(new URI(someUrl))` is available since Java 7. – assylias Mar 16 '15 at 12:09
  • 1
    else block can be done with `java.nio.file.Files#copy(java.nio.file.Path, java.nio.file.Path, java.nio.file.CopyOption...)` also available since 1.7 – bowmore Mar 16 '15 at 13:14
  • 3
    Check the example in the javadoc of FileVisitor: http://docs.oracle.com/javase/7/docs/api/java/nio/file/FileVisitor.html – assylias Mar 16 '15 at 13:27
  • 3
    What about this [org.apache.commons.io.FileUtils.copyDirectory(File, File)](https://commons.apache.org/proper/commons-io/javadocs/api-2.5/org/apache/commons/io/FileUtils.html) ... it does the job safety ... :D – udoline Jun 13 '19 at 07:31

7 Answers7

32

In this way the code looks a bit simpler

import static java.nio.file.StandardCopyOption.*;

public  void copyFolder(Path src, Path dest) throws IOException {
    try (Stream<Path> stream = Files.walk(src)) {
        stream.forEach(source -> copy(source, dest.resolve(src.relativize(source))));
    }
}

private void copy(Path source, Path dest) {
    try {
        Files.copy(source, dest, REPLACE_EXISTING);
    } catch (Exception e) {
        throw new RuntimeException(e.getMessage(), e);
    }
}
Christian Schneider
  • 19,420
  • 2
  • 39
  • 64
27

Using Files.walkFileTree:

  • you don't need to worry about closing Streams.
    (some other answers here forget that while using Files.walk)
  • handles IOException elegantly.
    (Some other answers here would become more difficult when adding proper exception handling instead of a simple printStackTrace)
    public void copyFolder(Path source, Path target, CopyOption... options)
            throws IOException {
        Files.walkFileTree(source, new SimpleFileVisitor<Path>() {

            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
                    throws IOException {
                Files.createDirectories(target.resolve(source.relativize(dir).toString()));
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
                    throws IOException {
                Files.copy(file, target.resolve(source.relativize(file).toString()), options);
                return FileVisitResult.CONTINUE;
            }
        });
    }

What this does is

  • walk recursively over all files in the directory.
  • When a directory is encountered (preVisitDirectory):
    create the corresponding one in the target directory.
  • When a regular file is encountered (visitFile):
    copy it.

options can be used to tailor the copy to your needs. For example to overwrite existing files in the target directory, use copyFolder(source, target, StandardCopyOption.REPLACE_EXISTING);

GingerPlusPlus
  • 5,336
  • 1
  • 29
  • 52
neXus
  • 2,005
  • 3
  • 29
  • 53
  • Much better than many other answers, for the reasons stated. One drawback that should be mentioned: when a security manager prevents access to some file, the copy of the files which cannot be accessed will silently fail. (This should be rare however, usually no security manager is used.) – Olivier Cailloux Apr 07 '20 at 00:04
  • This solution is ok if there are no symbolic links, otherwise, it will copy they target dir and turn the link into an empty directory with the link name. – Chris Wolf Jun 02 '20 at 21:18
  • 2
    If you want to follow symbolic links, you can replace [`Files.walkFileTree(source, visitor)`](https://docs.oracle.com/javase/8/docs/api/java/nio/file/Files.html#walkFileTree-java.nio.file.Path-java.nio.file.FileVisitor-) with [`Files.walkFileTree(source, EnumSet.of(FOLLOW_LINKS), Integer.MAX_VALUE, visitor)`](https://docs.oracle.com/javase/8/docs/api/java/nio/file/Files.html#walkFileTree-java.nio.file.Path-java.util.Set-int-java.nio.file.FileVisitor-) – neXus Jun 05 '20 at 09:22
16

How about the following code

public void copyFolder(File src, File dest) throws IOException {
        try (Stream<Path> stream = Files.walk(src.toPath())) {
            stream.forEachOrdered(sourcePath -> {

                try {
                    Files.copy(
                            /*Source Path*/
                            sourcePath,
                            /*Destination Path */
                            src.toPath().resolve(dest.toPath().relativize(sourcePath)));
                } catch (IOException e) {
                    throw new UncheckedIOException(e);
                }
            });
        }
    }
Mohit Kanwar
  • 2,962
  • 7
  • 39
  • 59
10

This version uses Files.walk and Path parameters as Java 8 suggests.

public static void copyFolder(Path src, Path dest) {
    try {
        Files.walk( src ).forEach( s -> {
            try {
                Path d = dest.resolve( src.relativize(s) );
                if( Files.isDirectory( s ) ) {
                    if( !Files.exists( d ) )
                        Files.createDirectory( d );
                    return;
                }
                Files.copy( s, d );// use flag to override existing
            } catch( Exception e ) {
                e.printStackTrace();
            }
        });
    } catch( Exception ex ) {
        ex.printStackTrace();
    }
}
Ahmed Ashour
  • 5,179
  • 10
  • 35
  • 56
Sasha Firsov
  • 699
  • 8
  • 9
1

and one more version:

static void copyFolder(File src, File dest){
    // checks
    if(src==null || dest==null)
        return;
    if(!src.isDirectory())
        return;
    if(dest.exists()){
        if(!dest.isDirectory()){
            //System.out.println("destination not a folder " + dest);
            return;
        }
    } else {
        dest.mkdir();
    }

    if(src.listFiles()==null || src.listFiles().length==0)
        return;

    String strAbsPathSrc = src.getAbsolutePath();
    String strAbsPathDest = dest.getAbsolutePath();

    try {
        Files.walkFileTree(src.toPath(), new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult visitFile(Path file,
                    BasicFileAttributes attrs) throws IOException {
                File dstFile = new File(strAbsPathDest + file.toAbsolutePath().toString().substring(strAbsPathSrc.length()));
                if(dstFile.exists())
                    return FileVisitResult.CONTINUE;

                if(!dstFile.getParentFile().exists())
                    dstFile.getParentFile().mkdirs();

                //System.out.println(file + " " + dstFile.getAbsolutePath());
                Files.copy(file, dstFile.toPath());

                return FileVisitResult.CONTINUE;
            }
        });

    } catch (IOException e) {
        //e.printStackTrace();
        return;
    }

    return;
}

its code use java8 Files.walkFileTree function.

pwipo
  • 463
  • 3
  • 7
0

my version:

static private void copyFolder(File src, File dest) {
    // checks
    if(src==null || dest==null)
        return;
    if(!src.isDirectory())
        return;
    if(dest.exists()){
        if(!dest.isDirectory()){
            //System.out.println("destination not a folder " + dest);
            return;
        }
    } else {
        dest.mkdir();
    }

    File[] files = src.listFiles();
    if(files==null || files.length==0)
        return;

    for(File file: files){
        File fileDest = new File(dest, file.getName());
        //System.out.println(fileDest.getAbsolutePath());
        if(file.isDirectory()){
            copyFolder(file, fileDest);
        }else{
            if(fileDest.exists())
                continue;

            try {
                Files.copy(file.toPath(), fileDest.toPath());
            } catch (IOException e) {
                //e.printStackTrace();
            }
        }
    }
}
pwipo
  • 463
  • 3
  • 7
  • 1
    Please consider adding some explanation about the code. – LittlePanda Apr 22 '15 at 14:44
  • I add some expensive checks. its usefull if no checks in external code, example - raw data from users. – pwipo Apr 22 '15 at 14:52
  • @pwipo I just wanted to thank you for this code, most of the examples I have found do not work but this works perfectly, you have saved me a lot of time by automating this, thank you!! – Tom Jun 14 '17 at 02:15
  • Really? Are you going to call listFiles() on the same object multiple times??? – Blake McBride Feb 16 '20 at 21:55
  • Correct me if I'm mistaken @blake-mcbride but I don't see how he is calling listFiles() on the same object? It's outside of the for loop and is only called again for recursion in a lower directory... – JohnRDOrazio Nov 02 '20 at 20:02
  • Clearly, it's not being called multiple times now.... (My comment was made 2/16. It was modified two days later..... – Blake McBride Nov 03 '20 at 21:58
-1

Can be used to copy source (file or directory) to target (directory)

void copy(Path source, Path target, boolean override) throws IOException {
    Path target = target.resolve(source.toFile().getName());
    Files.walkFileTree(source, new FileVisitor<Path>() {
        @Override
        public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
            Path targetDir = target.resolve(source.relativize(dir));
            if(Files.notExists(targetDir)) {
                Files.createDirectory(targetDir);
            }
            return FileVisitResult.CONTINUE;
        }

        @Override
        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
            Files.copy(file, target.resolve(source.relativize(file))));
            return FileVisitResult.CONTINUE;
        }

        @Override
        public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
            throw new RuntimeException("Copying file " + file + " failed", exc);
            // Consider looking at FileVisitResult options... 
        }

        @Override
        public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
            if (exc != null) {
                // TODO...
            }
            return FileVisitResult.CONTINUE; // Or whatever works for you
        }
    });
}