2012-04-13 22 views
15

Tôi có một InputStream mà tôi muốn viết vào một HttpServletResponse. Có phương pháp này, trong đó có quá nhiều thời gian do việc sử dụng các byte []Viết một InputStream vào một HttpServletResponse

InputStream is = getInputStream(); 
int contentLength = getContentLength(); 

byte[] data = new byte[contentLength]; 
is.read(data); 

//response here is the HttpServletResponse object 
response.setContentLength(contentLength); 
response.write(data); 

tôi đã tự hỏi điều gì có thể là cách tốt nhất để làm điều đó, về mặt tốc độ và hiệu quả.

Trả lời

41

Chỉ cần viết các khối thay vì sao chép toàn bộ khối vào bộ nhớ của Java trước tiên. Ví dụ cơ bản dưới đây viết nó trong các khối 10KB. Bằng cách này, bạn kết thúc với việc sử dụng bộ nhớ nhất quán chỉ có 10KB thay vì độ dài nội dung hoàn chỉnh. Ngoài ra, người dùng cuối sẽ bắt đầu nhận được các phần của nội dung sớm hơn nhiều.

response.setContentLength(getContentLength()); 
byte[] buffer = new byte[10240]; 

try (
    InputStream input = getInputStream(); 
    OutputStream output = response.getOutputStream(); 
) { 
    for (int length = 0; (length = input.read(buffer)) > 0;) { 
     output.write(buffer, 0, length); 
    } 
} 

Như creme de la Creme liên quan đến hiệu suất với, bạn có thể sử dụng nio Channels và trực tiếp phân bổ ByteBuffer. Tạo phương thức tiện ích/trình trợ giúp sau trong một số lớp tiện ích tùy chỉnh, ví dụ: Utils:

public static long stream(InputStream input, OutputStream output) throws IOException { 
    try (
     ReadableByteChannel inputChannel = Channels.newChannel(input); 
     WritableByteChannel outputChannel = Channels.newChannel(output); 
    ) { 
     ByteBuffer buffer = ByteBuffer.allocateDirect(10240); 
     long size = 0; 

     while (inputChannel.read(buffer) != -1) { 
      buffer.flip(); 
      size += outputChannel.write(buffer); 
      buffer.clear(); 
     } 

     return size; 
    } 
} 

Mà bạn sau đó sử dụng như sau:

response.setContentLength(getContentLength()); 
Utils.stream(getInputStream(), response.getOutputStream()); 
+0

Tôi đã hy vọng có thể có một cách khác, nhưng cảm ơn anyway –

+0

Cảm ơn rất nhiều BalusC, –

+2

Tất nhiên nhiều gói tiện ích có phương pháp này đã được xác định, vì vậy khi bạn bắt đầu sử dụng Guava ... http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/io /ByteStreams.html#copy(java.io.InputStream, java.io.OutputStream) –

1
BufferedInputStream in = null; 
BufferedOutputStream out = null; 
OutputStream os; 
os = new BufferedOutputStream(response.getOutputStream()); 
in = new BufferedInputStream(new FileInputStream(file)); 
out = new BufferedOutputStream(os); 
byte[] buffer = new byte[1024 * 8]; 
int j = -1; 
while ((j = in.read(buffer)) != -1) { 
    out.write(buffer, 0, j); 
} 
+0

Tôi wan để tránh việc sử dụng byte [], nếu có thể –

+0

@MuhammadSabry không có cách nào để đọc InputStream w/o sử dụng ' byte [] ' –

+0

Có gì sai với byte []. Bạn cần phải lưu trữ dữ liệu someware:} – MTilsted

0

Tôi nghĩ điều đó rất gần với cách tốt nhất, nhưng tôi sẽ đề xuất thay đổi sau. Sử dụng bộ đệm kích thước cố định (Nói 20K) và sau đó thực hiện đọc/ghi trong vòng lặp.

Đối với vòng lặp làm điều gì đó như

Byte buffer[]=new byte[20*1024]; 
outputStream=response.getOutputStream(); 
while(true) { 
    int readSize=is.read(buffer); 
    if(readSize==-1) 
    break; 
    outputStream.write(buffer,0,readSize); 
} 

ps: Chương trình của bạn sẽ không luôn luôn làm việc như là, vì đọc không phải lúc nào lấp đầy toàn bộ mảng bạn cho nó.

+0

chính xác những gì bạn có nghĩa là bằng cách đọc không điền vào toàn bộ mảng bạn cung cấp cho nó? –

+1

Đọc không phải luôn luôn điền vào mảng đầu vào. Vì vậy, bạn cần phải kiểm tra giá trị mà đọc trở lại đó là số byte đọc. (Xem http://docs.oracle.com/javase/6/docs/api/java/io/InputStream.html#read%28byte[]%29) – MTilsted

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