jdk/src/share/sample/nio/file/Copy.java
changeset 2057 3acf8e5e2ca0
child 2629 06517d95fadd
equal deleted inserted replaced
2056:115e09b7a004 2057:3acf8e5e2ca0
       
     1 /*
       
     2  * Copyright 2008-2009 Sun Microsystems, Inc.  All Rights Reserved.
       
     3  *
       
     4  * Redistribution and use in source and binary forms, with or without
       
     5  * modification, are permitted provided that the following conditions
       
     6  * are met:
       
     7  *
       
     8  *   - Redistributions of source code must retain the above copyright
       
     9  *     notice, this list of conditions and the following disclaimer.
       
    10  *
       
    11  *   - Redistributions in binary form must reproduce the above copyright
       
    12  *     notice, this list of conditions and the following disclaimer in the
       
    13  *     documentation and/or other materials provided with the distribution.
       
    14  *
       
    15  *   - Neither the name of Sun Microsystems nor the names of its
       
    16  *     contributors may be used to endorse or promote products derived
       
    17  *     from this software without specific prior written permission.
       
    18  *
       
    19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
       
    20  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
       
    21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
       
    22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
       
    23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
       
    24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
       
    25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
       
    26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
       
    27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
       
    28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
       
    29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    30  */
       
    31 
       
    32 import java.nio.file.*;
       
    33 import static java.nio.file.StandardCopyOption.*;
       
    34 import java.nio.file.attribute.*;
       
    35 import static java.nio.file.FileVisitResult.*;
       
    36 import java.io.IOException;
       
    37 import java.util.*;
       
    38 
       
    39 /**
       
    40  * Sample code that copies files in a similar manner to the cp(1) program.
       
    41  */
       
    42 
       
    43 public class Copy {
       
    44 
       
    45     /**
       
    46      * Returns {@code true} if okay to overwrite a  file ("cp -i")
       
    47      */
       
    48     static boolean okayToOverwrite(FileRef file) {
       
    49         String answer = System.console().readLine("overwrite %s (yes/no)? ", file);
       
    50         return (answer.equalsIgnoreCase("y") || answer.equalsIgnoreCase("yes"));
       
    51     }
       
    52 
       
    53     /**
       
    54      * Copy source file to target location. If {@code prompt} is true then
       
    55      * prompted user to overwrite target if it exists. The {@code preserve}
       
    56      * parameter determines if file attributes should be copied/preserved.
       
    57      */
       
    58     static void copyFile(Path source, Path target, boolean prompt, boolean preserve) {
       
    59         CopyOption[] options = (preserve) ?
       
    60             new CopyOption[] { COPY_ATTRIBUTES, REPLACE_EXISTING } :
       
    61             new CopyOption[] { REPLACE_EXISTING };
       
    62         if (!prompt || target.notExists() || okayToOverwrite(target)) {
       
    63             try {
       
    64                 source.copyTo(target, options);
       
    65             } catch (IOException x) {
       
    66                 System.err.format("Unable to create: %s: %s%n", target, x);
       
    67             }
       
    68         }
       
    69     }
       
    70 
       
    71     /**
       
    72      * A {@code FileVisitor} that copies a file-tree ("cp -r")
       
    73      */
       
    74     static class TreeCopier implements FileVisitor<Path> {
       
    75         private final Path source;
       
    76         private final Path target;
       
    77         private final boolean prompt;
       
    78         private final boolean preserve;
       
    79 
       
    80         TreeCopier(Path source, Path target, boolean prompt, boolean preserve) {
       
    81             this.source = source;
       
    82             this.target = target;
       
    83             this.prompt = prompt;
       
    84             this.preserve = preserve;
       
    85         }
       
    86 
       
    87         @Override
       
    88         public FileVisitResult preVisitDirectory(Path dir) {
       
    89             // before visiting entries in a directory we copy the directory
       
    90             // (okay if directory already exists).
       
    91             CopyOption[] options = (preserve) ?
       
    92                 new CopyOption[] { COPY_ATTRIBUTES } : new CopyOption[0];
       
    93 
       
    94             Path newdir = target.resolve(source.relativize(dir));
       
    95             try {
       
    96                 dir.copyTo(newdir, options);
       
    97             } catch (FileAlreadyExistsException x) {
       
    98                 // ignore
       
    99             } catch (IOException x) {
       
   100                 System.err.format("Unable to create: %s: %s%n", newdir, x);
       
   101                 return SKIP_SUBTREE;
       
   102             }
       
   103             return CONTINUE;
       
   104         }
       
   105 
       
   106         @Override
       
   107         public FileVisitResult preVisitDirectoryFailed(Path dir, IOException exc) {
       
   108             System.err.format("Unable to copy: %s: %s%n", dir, exc);
       
   109             return CONTINUE;
       
   110         }
       
   111 
       
   112         @Override
       
   113         public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
       
   114             if (attrs.isDirectory()) {
       
   115                 System.err.println("cycle detected: " + file);
       
   116             } else {
       
   117                 copyFile(file, target.resolve(source.relativize(file)),
       
   118                          prompt, preserve);
       
   119             }
       
   120             return CONTINUE;
       
   121         }
       
   122 
       
   123         @Override
       
   124         public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
       
   125             // fix up modification time of directory when done
       
   126             if (exc == null && preserve) {
       
   127                 try {
       
   128                     BasicFileAttributes attrs = Attributes.readBasicFileAttributes(dir);
       
   129                     Path newdir = target.resolve(source.relativize(dir));
       
   130                     Attributes.setLastModifiedTime(newdir,
       
   131                         attrs.lastModifiedTime(), attrs.resolution());
       
   132                 } catch (IOException x) {
       
   133                     // ignore
       
   134                 }
       
   135             }
       
   136             return CONTINUE;
       
   137         }
       
   138 
       
   139         @Override
       
   140         public FileVisitResult visitFileFailed(Path file, IOException exc) {
       
   141             System.err.format("Unable to copy: %s: %s%n", file, exc);
       
   142             return CONTINUE;
       
   143         }
       
   144     }
       
   145 
       
   146     static void usage() {
       
   147         System.err.println("java Copy [-ip] source... target");
       
   148         System.err.println("java Copy -r [-ip] source-dir... target");
       
   149         System.exit(-1);
       
   150     }
       
   151 
       
   152     public static void main(String[] args) throws IOException {
       
   153         boolean recursive = false;
       
   154         boolean prompt = false;
       
   155         boolean preserve = false;
       
   156 
       
   157         // process options
       
   158         int argi = 0;
       
   159         while (argi < args.length) {
       
   160             String arg = args[argi];
       
   161             if (!arg.startsWith("-"))
       
   162                 break;
       
   163             if (arg.length() < 2)
       
   164                 usage();
       
   165             for (int i=1; i<arg.length(); i++) {
       
   166                 char c = arg.charAt(i);
       
   167                 switch (c) {
       
   168                     case 'r' : recursive = true; break;
       
   169                     case 'i' : prompt = true; break;
       
   170                     case 'p' : preserve = true; break;
       
   171                     default : usage();
       
   172                 }
       
   173             }
       
   174             argi++;
       
   175         }
       
   176 
       
   177         // remaining arguments are the source files(s) and the target location
       
   178         int remaining = args.length - argi;
       
   179         if (remaining < 2)
       
   180             usage();
       
   181         Path[] source = new Path[remaining-1];
       
   182         int i=0;
       
   183         while (remaining > 1) {
       
   184             source[i++] = Paths.get(args[argi++]);
       
   185             remaining--;
       
   186         }
       
   187         Path target = Paths.get(args[argi]);
       
   188 
       
   189         // check if target is a directory
       
   190         boolean isDir = false;
       
   191         try {
       
   192             isDir = Attributes.readBasicFileAttributes(target).isDirectory();
       
   193         } catch (IOException x) {
       
   194         }
       
   195 
       
   196         // copy each source file/directory to target
       
   197         for (i=0; i<source.length; i++) {
       
   198             Path dest = (isDir) ? target.resolve(source[i].getName()) : target;
       
   199 
       
   200             if (recursive) {
       
   201                 // follow links when copying files
       
   202                 EnumSet<FileVisitOption> opts = EnumSet.of(FileVisitOption.FOLLOW_LINKS);
       
   203                 TreeCopier tc = new TreeCopier(source[i], dest, prompt, preserve);
       
   204                 Files.walkFileTree(source[i], opts, -1, tc);
       
   205             } else {
       
   206                 // not recursive so source must not be a directory
       
   207                 try {
       
   208                     if (Attributes.readBasicFileAttributes(source[i]).isDirectory()) {
       
   209                         System.err.format("%s: is a directory%n", source[i]);
       
   210                         continue;
       
   211                     }
       
   212                 } catch (IOException x) { }
       
   213                 copyFile(source[i], dest, prompt, preserve);
       
   214             }
       
   215         }
       
   216     }
       
   217 }