[java] Java로 파일을 복사하는 표준 간결한 방법?

Java에서 파일을 복사하는 유일한 방법은 스트림 열기, 버퍼 선언, 한 파일 읽기, 반복 및 다른 스팀에 쓰는 것만으로 항상 귀찮았습니다. 웹은 이러한 유형의 솔루션의 유사하지만 여전히 약간 다른 구현으로 흩어져 있습니다.

Java 언어의 범위 내에 머무르는 더 좋은 방법이 있습니까 (즉, OS 특정 명령 실행과 관련이 없음)? 아마도 일부 신뢰할 수있는 오픈 소스 유틸리티 패키지에서이 기본 구현을 모호하게하고 한 줄 솔루션을 제공 할 것입니까?



답변

툴킷이 위에서 언급했듯이 Apache Commons IO는 특히 FileUtils 입니다. copyFile () ; 그것은 당신을 위해 모든 무거운 리프팅을 처리합니다.

그리고 포스트 스크립트로 최신 버전의 FileUtils (예 : 2.0.1 릴리스)에 파일 복사에 NIO 사용이 추가되었습니다. NIO 루틴은 Java 계층을 통해 바이트를 읽고 쓰는 방식으로 처리하지 않고 OS / 파일 시스템에 직접 복사하는 것을 연기하기 때문에 NIO는 파일 복사 성능을 크게 향상시킬 수 있습니다 . 따라서 성능을 찾고 있다면 최신 버전의 FileUtils를 사용하고 있는지 확인하는 것이 좋습니다.


답변

나는 아파치 커먼즈와 같은 메가 API의 사용을 피할 것입니다. 이것은 간단한 조작이며 새로운 NIO 패키지의 JDK에 내장되어 있습니다. 이전 답변에서 이미 연결되어 있었지만 NIO API의 주요 방법은 새로운 기능 “transferTo”및 “transferFrom”입니다.

http://java.sun.com/javase/6/docs/api/java/nio/channels/FileChannel.html#transferTo(long,%20long,%20java.nio.channels.WritableByteChannel)

링크 된 기사 중 하나는 transferFrom을 사용하여이 함수를 코드에 통합하는 방법에 대한 훌륭한 방법을 보여줍니다.

public static void copyFile(File sourceFile, File destFile) throws IOException {
    if(!destFile.exists()) {
        destFile.createNewFile();
    }

    FileChannel source = null;
    FileChannel destination = null;

    try {
        source = new FileInputStream(sourceFile).getChannel();
        destination = new FileOutputStream(destFile).getChannel();
        destination.transferFrom(source, 0, source.size());
    }
    finally {
        if(source != null) {
            source.close();
        }
        if(destination != null) {
            destination.close();
        }
    }
}

NIO를 배우는 것은 약간 까다로울 수 있으므로, 밤새 NIO를 배우기 전에이 메커니즘을 신뢰하고 싶을 것입니다. 개인적인 경험으로는 경험이없고 java.io 스트림을 통해 IO에 소개 된 경우 배우기가 매우 어려울 수 있습니다.


답변

이제 Java 7에서는 다음 try-with-resource 구문을 사용할 수 있습니다.

public static void copyFile( File from, File to ) throws IOException {

    if ( !to.exists() ) { to.createNewFile(); }

    try (
        FileChannel in = new FileInputStream( from ).getChannel();
        FileChannel out = new FileOutputStream( to ).getChannel() ) {

        out.transferFrom( in, 0, in.size() );
    }
}

또는 Java 7에 도입 된 새로운 Files 클래스를 사용하여이 작업을 수행 할 수도 있습니다.

public static void copyFile( File from, File to ) throws IOException {
    Files.copy( from.toPath(), to.toPath() );
}

꽤 멋져요?


답변

  • 이러한 방법은 성능을 고려하여 설계되었습니다 (운영 체제 고유 I / O와 통합).
  • 이 메소드는 파일, 디렉토리 및 링크와 함께 작동합니다.
  • 제공된 각 옵션은 생략 될 수 있습니다 (선택 사항).

유틸리티 클래스

package com.yourcompany.nio;

class Files {

    static int copyRecursive(Path source, Path target, boolean prompt, CopyOptions options...) {
        CopyVisitor copyVisitor = new CopyVisitor(source, target, options).copy();
        EnumSet<FileVisitOption> fileVisitOpts;
        if (Arrays.toList(options).contains(java.nio.file.LinkOption.NOFOLLOW_LINKS) {
            fileVisitOpts = EnumSet.noneOf(FileVisitOption.class)
        } else {
            fileVisitOpts = EnumSet.of(FileVisitOption.FOLLOW_LINKS);
        }
        Files.walkFileTree(source[i], fileVisitOpts, Integer.MAX_VALUE, copyVisitor);
    }

    private class CopyVisitor implements FileVisitor<Path>  {
        final Path source;
        final Path target;
        final CopyOptions[] options;

        CopyVisitor(Path source, Path target, CopyOptions options...) {
             this.source = source;  this.target = target;  this.options = options;
        };

        @Override
        FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
        // before visiting entries in a directory we copy the directory
        // (okay if directory already exists).
        Path newdir = target.resolve(source.relativize(dir));
        try {
            Files.copy(dir, newdir, options);
        } catch (FileAlreadyExistsException x) {
            // ignore
        } catch (IOException x) {
            System.err.format("Unable to create: %s: %s%n", newdir, x);
            return SKIP_SUBTREE;
        }
        return CONTINUE;
    }

    @Override
    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
        Path newfile= target.resolve(source.relativize(file));
        try {
            Files.copy(file, newfile, options);
        } catch (IOException x) {
            System.err.format("Unable to copy: %s: %s%n", source, x);
        }
        return CONTINUE;
    }

    @Override
    public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
        // fix up modification time of directory when done
        if (exc == null && Arrays.toList(options).contains(COPY_ATTRIBUTES)) {
            Path newdir = target.resolve(source.relativize(dir));
            try {
                FileTime time = Files.getLastModifiedTime(dir);
                Files.setLastModifiedTime(newdir, time);
            } catch (IOException x) {
                System.err.format("Unable to copy all attributes to: %s: %s%n", newdir, x);
            }
        }
        return CONTINUE;
    }

    @Override
    public FileVisitResult visitFileFailed(Path file, IOException exc) {
        if (exc instanceof FileSystemLoopException) {
            System.err.println("cycle detected: " + file);
        } else {
            System.err.format("Unable to copy: %s: %s%n", file, exc);
        }
        return CONTINUE;
    }
}

디렉토리 또는 파일 복사

long bytes = java.nio.file.Files.copy(
                 new java.io.File("<filepath1>").toPath(),
                 new java.io.File("<filepath2>").toPath(),
                 java.nio.file.StandardCopyOption.REPLACE_EXISTING,
                 java.nio.file.StandardCopyOption.COPY_ATTRIBUTES,
                 java.nio.file.LinkOption.NOFOLLOW_LINKS);

디렉토리 또는 파일 이동

long bytes = java.nio.file.Files.move(
                 new java.io.File("<filepath1>").toPath(),
                 new java.io.File("<filepath2>").toPath(),
                 java.nio.file.StandardCopyOption.ATOMIC_MOVE,
                 java.nio.file.StandardCopyOption.REPLACE_EXISTING);

디렉토리 또는 파일을 재귀 적으로 복사

long bytes = com.yourcompany.nio.Files.copyRecursive(
                 new java.io.File("<filepath1>").toPath(),
                 new java.io.File("<filepath2>").toPath(),
                 java.nio.file.StandardCopyOption.REPLACE_EXISTING,
                 java.nio.file.StandardCopyOption.COPY_ATTRIBUTES
                 java.nio.file.LinkOption.NOFOLLOW_LINKS );


답변

Java 7에서는 쉽습니다 …

File src = new File("original.txt");
File target = new File("copy.txt");

Files.copy(src.toPath(), target.toPath(), StandardCopyOption.REPLACE_EXISTING);


답변

파일을 복사하여 대상 경로에 저장하려면 아래 방법을 사용하십시오.

public void copy(File src, File dst) throws IOException {
    InputStream in = new FileInputStream(src);
    try {
        OutputStream out = new FileOutputStream(dst);
        try {
            // Transfer bytes from in to out
            byte[] buf = new byte[1024];
            int len;
            while ((len = in.read(buf)) > 0) {
                out.write(buf, 0, len);
            }
        } finally {
            out.close();
        }
    } finally {
        in.close();
    }
}


답변

이러한 모든 메커니즘은 권한과 같은 메타 데이터가 아니라 파일의 내용 만 복사합니다. 따라서 리눅스에서 실행 가능한 .sh 파일을 복사하거나 옮기려면 새 파일을 실행할 수 없습니다.

명령 줄에서 복사하는 것과 동일한 결과를 얻으려면 파일을 실제로 복사하거나 이동하려면 실제로 기본 도구를 사용해야합니다. 쉘 스크립트 또는 JNI입니다.

분명히 이것은 Java 7- http : //today.java.net/pub/a/today/2008/07/03/jsr-203-new-file-apis.html 에서 수정되었을 수 있습니다 . 손가락이 넘어졌다!