2013-05-16 27 views
12

Tôi đang sử dụng cách sau để viết InputStream-File:Làm thế nào để sử dụng NIO để ghi InputStream vào File?

private void writeToFile(InputStream stream) throws IOException { 
    String filePath = "C:\\Test.jpg"; 
    FileChannel outChannel = new FileOutputStream(filePath).getChannel();  
    ReadableByteChannel inChannel = Channels.newChannel(stream); 
    ByteBuffer buffer = ByteBuffer.allocate(1024); 

    while(true) { 
     if(inChannel.read(buffer) == -1) { 
      break; 
     } 

     buffer.flip(); 
     outChannel.write(buffer); 
     buffer.clear(); 
    } 

    inChannel.close(); 
    outChannel.close(); 
} 

tôi đã tự hỏi nếu điều này là đúng cách để sử dụng nio. Tôi đã đọc một phương pháp FileChannel.transferFrom, trong đó có ba tham số:

  1. ReadableByteChannel src
  2. vị trí dài
  3. đếm dài

Trong trường hợp của tôi, tôi chỉ có src, tôi không có positioncount, có cách nào tôi có thể sử dụng phương pháp này để tạo tệp không?

Ngoài ra đối với hình ảnh là có cách nào tốt hơn để tạo hình ảnh chỉ từ InputStream và NIO?

Mọi thông tin sẽ rất hữu ích đối với tôi. Có những câu hỏi tương tự ở đây, trong SO, nhưng tôi không thể tìm thấy bất kỳ giải pháp cụ thể nào bao gồm trường hợp của tôi.

+5

Tại sao lại theo cách phức tạp như vậy? Bạn có thể làm tương tự trong một dòng: 'Files.copy (stream, new File (" C: \\ Test.jpg "). ToPath());' – Jesper

Trả lời

7

Không đúng. Bạn có nguy cơ mất dữ liệu. Các kinh điển nio loop bản là như sau:

while (in.read(buffer) >= 0 || buffer.position() > 0) 
{ 
    buffer.flip(); 
    out.write(buffer); 
    buffer.compact(); 
} 

Lưu ý các điều kiện vòng lặp thay đổi, mà chăm sóc xả nước đầu ra ở EOS, và việc sử dụng các compact() thay vì clear(), mà sẽ chăm sóc về khả năng viết ngắn.

Tương tự, kinh điển transferTo()/transferFrom() vòng lặp như sau:

long offset = 0; 
long quantum = 1024*1024; // or however much you want to transfer at a time 
long count; 
while ((count = out.transferFrom(in, offset, quantum)) > 0) 
{ 
    offset += count; 
} 

Nó phải được gọi trong một vòng lặp, vì nó không đảm bảo sẽ chuyển toàn bộ lượng tử.

+0

Nếu transferFrom trả về 0 nó không có nghĩa là tất cả các byte thực sự là được chuyển giao. Để chính xác 100%, chúng tôi cần biết trước số lượng dự kiến ​​từ InputStream và lặp lại cho đến khi chúng tôi chuyển tất cả. Bạn có đồng ý không? –

+0

Có, tôi có. Đó là một điều kỳ lạ là không có chỉ thị EOS thích hợp từ các API này. – EJP

37

Tôi sẽ sử dụng Files.copy

Files.copy(is, Paths.get(filePath)); 

như đối với phiên bản của bạn

  1. ByteBuffer.allocateDirect nhanh - Java sẽ cố gắng hết sức để thực hiện bản địa I/O hoạt động trực tiếp trên nó.

  2. Đóng không đáng tin cậy, nếu lần đầu tiên thất bại thứ hai sẽ không bao giờ thực thi. Thay vào đó, hãy sử dụng try-with-resources, Kênh cũng là AutoCloseable.

+0

'transferFrom()' và 'transferTo()' phải được gọi trong một vòng lặp. Không có gì đảm bảo rằng họ chuyển số lượng yêu cầu. Đó là lý do tại sao họ trả lại một số. – EJP

+0

Sử dụng Files.copy (fileInputStream, filePath, StandardCopyOption.THAY THẾ CÁI ĐÃ TỒN TẠI); nếu tệp đã tồn tại. – Justas

Các vấn đề liên quan