2011-01-19 39 views
12

Khi tôi muốn ghi toàn bộ nội dung của tệp vào OutputStream, tôi thường phân bổ bộ đệm dưới dạng byte[], sau đó tạo vòng lặp for thành read dữ liệu từ tệp InputStream vào bộ đệm và ghi nội dung đệm vào OutputStream, cho đến khi InputStream không còn byte nào.Có cách nào tốt hơn để ghi toàn bộ nội dung của tệp vào OutputStream không?

Điều này có vẻ hơi vụng về với tôi. Có cách nào tốt hơn để làm điều này?

Ngoài ra, tôi luôn không chắc chắn về kích thước bộ đệm. Thông thường, tôi phân bổ 1024 byte, bởi vì nó chỉ cảm thấy tốt. Có cách nào tốt hơn để xác định kích thước bộ đệm hợp lý không?

Trong trường hợp hiện tại, tôi muốn sao chép toàn bộ nội dung của tệp vào luồng đầu ra ghi nội dung của phản hồi HTTP. Vì vậy, đây không phải là câu hỏi về cách sao chép tệp trên hệ thống tệp.

Trả lời

19

Đối với Java 1.7+, bạn có thể sử dụng Files.copy(Path, OutputStream), ví dụ:

HttpServletResponse response = // ... 
File toBeCopied = // ... 

try (OutputStream out = response.getOutputStream()) { 
    Path path = toBeCopied.toPath(); 
    Files.copy(path, out); 
    out.flush(); 
} catch (IOException e) { 
    // handle exception 
} 

Note, kể từ khi bạn đang đối phó với HttpServletResponse là cũng là một ý tưởng tốt để thiết lập tiêu đề trả lời đúng. Thêm các dòng sau trước bạn sao chép các tập tin dữ liệu thực tế để phản ứng:

String mimeType = URLConnection.guessContentTypeFromName(toBeCopied.getName()); 
String contentDisposition = String.format("attachment; filename=%s", toBeCopied.getName()); 
int fileSize = Long.valueOf(toBeCopied.length()).intValue(); 

response.setContentType(mimeType); 
response.setHeader("Content-Disposition", contentDisposition); 
response.setContentLength(fileSize); 

Lưu ý, các mã hóa của tên tập tin thông qua với việc bố trí nội dung rất quan trọng, xem this question.

+0

Kiểm tra đơn vị của tôi có thể xác minh những gì được ghi vào OutputStream? ServletOutputStream mockOutput = mock (ServletOutputStream.class); \t \t khi (response.getOutputStream()). ThenReturn (mockOutput); –

8

Với commons-io bạn có một giải pháp một dòng:

IOUtils.copy(yourFileInputStream, outputStream); 

Lưu ý rằng bạn phải đóng suối của bạn bằng tay (hoặc bằng cách IOUtils.closeQuitely(..))

+0

Đây cũng là đề xuất của tôi. Mặc dù những gì nó làm là điều tương tự. – rfeak

+0

có, chỉ ngắn hơn. Và bộ đệm tự động – Bozho

+0

Điều đó trông rất đẹp. Nhưng đối với nhiệm vụ đơn giản này, có vẻ như một chút quá liều với tôi để đưa vào một thư viện khác. Tất nhiên, nếu có nhiều lý do để bao gồm Commons-IO, thì đây sẽ là giải pháp lựa chọn. – Madoc

21

Apache Commons-IO:

IOUtils.copy(fileInputStream,outputStream); 

JDK NIO

new FileInputStream(file).getChannel().transferTo(otherChannel); 
+3

+1 cho NIO .... – Bozho

+0

Rất tiếc. Tôi đã đưa ra một bình luận ngắn về Commons-IO tại câu trả lời của Bozho. Nhưng giải pháp kênh là chính xác những gì tôi đang tìm kiếm. Cảm ơn rất nhiều, tất cả các kênh NIO đã truyền cho tôi bởi vì tôi đã học Java IO trước khi NIO tồn tại. Và, nhân tiện: 9 phút! Nó gần như nhanh như chớp. – Madoc

+2

đừng quên đóng 'FileInputStream' – yegor256

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