2011-10-13 2 views
0

다음 예제는 스트림을 사용하여 파일을 복사하는 방법을 보여줍니다. 상기의 코드 용 스트림이있는 파일 복사

private void copyWithStreams(File aSourceFile, File aTargetFile, boolean aAppend) { 
log("Copying files with streams."); 
ensureTargetDirectoryExists(aTargetFile.getParentFile()); 
InputStream inStream = null; 
OutputStream outStream = null; 
try{ 
    try { 
    byte[] bucket = new byte[32*1024]; 
    inStream = new BufferedInputStream(new FileInputStream(aSourceFile)); 
    outStream = new BufferedOutputStream(new FileOutputStream(aTargetFile, aAppend)); 
    int bytesRead = 0; 
    while(bytesRead != -1){ 
     bytesRead = inStream.read(bucket); //-1, 0, or more 
     if(bytesRead > 0){ 
     outStream.write(bucket, 0, bytesRead); 
     } 
    } 
    } 
    finally { 
    if (inStream != null) inStream.close(); 
    if (outStream != null) outStream.close(); 
    } 
} 
catch (FileNotFoundException ex){ 
    log("File not found: " + ex); 
} 
catch (IOException ex){ 
    log(ex); 
} 
} 

private void ensureTargetDirectoryExists(File aTargetDir){ 
if(!aTargetDir.exists()){ 
    aTargetDir.mkdirs(); 
} 
} 
private static void log(Object aThing){ 
    System.out.println(String.valueOf(aThing)); 
} 

는 I 네 포인트에 대해 혼란 느낌 :

1) 버킷 바이트 [] = 버킷 새로운 바이트 [32 * 1024]로 분배한다; 32 * 1024와 같은 크기를 선택하기위한 기준이 있습니까?

2) 왜 여기에 "붙잡아 야"합니까? 작문 프로그램에 캐치를 포함시키는 규칙이 있습니까?

3) "try"사용법에 대해서는 아직 명확하지 않습니다. 저자가이 프로그램에서 중첩 된 시도를 사용하는 것 같습니다.

+0

왜 File.Copy를 사용하지 않는가 http://msdn.microsoft.com/en-us/library/system.io.file.copy%28v=VS.110%29.aspx 또는 파일 크기가 클 경우 이 http://stackoverflow.com/questions/92114/how-can-i-copy-a-large-file-on-windows-without-copyfile-or-copyfileex – rabs

+4

@rabs - 이것은 C# 또는 아무것도 관련이 없습니다 마이크로 소프트에게. –

+2

그건 겨우 세입니다. –

답변

0

1) 바이트 배열의 크기를 정의 할 기준이 없습니다.주어진 코드에서 32kbytes를 사용했지만 어떤 값이라도 사용할 수 있습니다. 바이트 배열의 크기와 파일 크기는 파일을 읽는 횟수를 결정합니다. 버퍼가 클수록 읽기 호출은 적지 만 작은 파일을 사용하는 경우에는 필요하지 않습니다.

2) Java에서 예외를 throw 할 수있는 메서드를 사용할 때마다 해당 예외를 catch하고 그 예외를 처리해야합니다. 코드에서 예외를 처리하거나 (일반적으로 스택 추적을 디버깅 목적으로 인쇄) throw 할 수 있습니다. 즉, 누군가가 코드를 사용할 때 코드의 예외를 잡아야합니다.

3) 그가 한 것은 가능한 두 가지 예외를 파악하고 어떤 것이 발생하는지 지정하는 것입니다. FileNotFoundException이 (가) IOException까지 확장 되었기 때문에 그는 단지 하나의 시도 만 사용하고 IOException 만 잡을 수 있습니다. IOExceptionFileNotFoundException 또는 기타 IOException인지 여부를 알 수 있도록 코딩했습니다. 개인적으로 필자가 작성한 것과 같은 방식으로 코드를 작성하지는 않겠지 만 쉽게 읽을 수는 없습니다.

 System.out.println("Copying files with streams."); 
    InputStream inStream = null; 
    OutputStream outStream = null; 
    try { 
     inStream = new BufferedInputStream(new FileInputStream(aSourceFile)); 
     outStream = new BufferedOutputStream(new FileOutputStream(aTargetFile, aAppend)); 
    } catch (FileNotFoundException ex){ 
     // TODO Handle FileNotFoundException 
     ex.printStackTrace(); 
    } 
    try { 
     byte[] bucket = new byte[32*1024]; 
     int bytesRead = 0; 
     while(bytesRead != -1){ 
      bytesRead = inStream.read(bucket); //-1, 0, or more 
      outStream.write(bucket, 0, bytesRead); 
     } 
    } catch (IOException ex){ 
     // TODO Handle IOException 
     ex.printStackTrace(); 
    } finally { 
     try { 
      if (inStream != null) inStream.close(); 
      if (outStream != null) outStream.close(); 
     } catch (IOException ex){ 
      // TODO Handle IOException 
      ex.printStackTrace(); 
     } 
    } 

그것은 같은 물건을 수행합니다

아마 당신이 시도하고이나 저전압을 이해하기 쉽게 얻는 코드를 재 작성.

+3

예외가 throw되면 스트림이 절대로 닫히지 않습니다. 여기에는 큰 차이가 있습니다. – bdares

+0

잘 고지 그것을 고쳤다. 감사. – oesgalha

1
  1. 것은 우리는 당신이 편안하게 메모리에 전체 파일을 맞지 않을 수 있음을 가정합니다, 그래서 우리는 한 번에 작은 덩어리를 선택, 프로세스는 다음 다음 청크를 잡아. 이 경우 32 킬로바이트를 사용하고 있습니다. 더 많거나 적게 사용할 수 있지만 하드 드라이브 섹터 크기 (일반적으로 4KB)의 (작은) 배수로 작업하면 더 효율적으로 IO 작업 수가 줄어 듭니다.

  2. 예외를 throw하는 중이거나 예외를 throw하는 메서드를 호출하는 경우 처리해야합니다. try{}catch{} (또는 finally{}) 문 블록으로 둘러싸거나이 예외라고하는 어떤 방법 으로든 예외를 던질 수 있습니다. 이 경우 try{} 문을 사용하므로 함께 제공되는 catchfinally 문을 사용할 수 있습니다.

  3. 저자는 불필요한 작업을 수행했습니다. 그는 try{}이라는 단일 문자를 사용하고 catch{} 문 다음에 finally{} 블록을 배치 할 수있었습니다. 대신 내부 try{}finally{} 블록을 실행 한 후 외부 try{}으로 예외를 전달합니다. 그 후 어떤 유형의 Exception이 던져 졌는지에 따라 catch{} 블록이 활성화됩니다.

+0

# 1의 경우 더 큰 * 블록 크기 (예 : 1MB)가 더 빠르지 않습니까? –

+0

@ 기계식 * 아마도 * 예. 하지만 적어도 OS와 파일 시스템에 달려 있습니다. –

+0

@ 기계식 확실하지만 얼마나 빨라 졌습니까? 수익률 감소 법이 있습니다. 2 바이트의 버퍼가 1 바이트의 버퍼보다 ​​좋으며 두 배가되면 추세가 계속되지만 이점은 각 단계마다 감소합니다. – EJP

1

1) 32 * 1024는 NTFS 볼륨을 포맷 할 때 기본 할당 단위 크기라고 생각되는 32 킬로바이트입니다. 기본 파일 시스템을 일치 시키면 제대로 캐싱하지 않으면 디스크의 섹터를 다시 쓰지 않으므로 성능이 약간 향상 될 수 있습니다. 버퍼가 클수록 일반적으로 작업이 더 부드럽습니다. 작은 장치에서 거대한 버퍼를 사용할 수는 없지만 (휴대폰은 점점 더 많은 메모리를 가지고 있습니다)

2) 여기 잡기는 매우 짜증나게 할 수 있습니다. 파일을 복사하고 원래 파일이 존재하지 않는다면,이 메소드를 호출하는 프로그램은 로그가된다. 이 메소드는 예외를 다시 던질 수 있고 호출 프로그램은 발견되지 않은 파일을 처리합니다. 입출력 문제와 동일합니다.

3) 최종 결과는 어떤 일이 발생하든 리소스가 닫히는 것을 보장하기 때문에 중요합니다. 중첩 된 try 문을 다른 예외를 로깅 한 후 리소스를 닫은 상태로 유지하면 실제로 런타임에 이점이 없습니다. (사소한 점, inStream을 닫는 동안 예외가 throw되는 경우 outStream은 닫히지 않으며 다른 예외는 손실됩니다.) 프로그래머는 읽기와 쓰기에 가까운 문장을 사용하는 것이 더 깔끔하다고 생각했을 수도 있지만 바깥 쪽 시도로 잘 옮길 수 있습니다.