Java 从URL读取InputStream并写入HttpServletResponse,而不创建临时文件

Java 从URL读取InputStream并写入HttpServletResponse,而不创建临时文件,java,Java,我尝试从URL读取InputStream并直接写入HttpServletResponse,而无需在HttpServlet中创建临时文件,但未能获得文件的实际内容长度。有人告诉我,如果不读取数据流,就无法确定数据流中的数据量。有人能帮我吗?我非常感谢。我使用这段代码,不进行内容长度管理(IOUtils在commons io中,不创建临时文件),但可以处理大小文件: public static void downloadFile(HttpServletResponse response, Input

我尝试从URL读取InputStream并直接写入HttpServletResponse,而无需在HttpServlet中创建临时文件,但未能获得文件的实际内容长度。有人告诉我,如果不读取数据流,就无法确定数据流中的数据量。有人能帮我吗?我非常感谢。

我使用这段代码,不进行内容长度管理(IOUtils在commons io中,不创建临时文件),但可以处理大小文件:

public static void downloadFile(HttpServletResponse response, InputStream inputStream, String fileName,
        String contentType) throws IOException {

    response.reset();
    response.setHeader("Content-disposition", String.format("attachment; filename=\"%s\"",
            fileName));

    if (contentType != null) {
        response.setHeader("Content-Type", contentType);
    }

    OutputStream output = response.getOutputStream();

    IOUtils.copy(inputStream, output);

    output.flush();
    output.close();
}

我使用这段代码,不进行内容长度管理(IOUtils在commons io中,不创建临时文件),但可以处理大小文件:

public static void downloadFile(HttpServletResponse response, InputStream inputStream, String fileName,
        String contentType) throws IOException {

    response.reset();
    response.setHeader("Content-disposition", String.format("attachment; filename=\"%s\"",
            fileName));

    if (contentType != null) {
        response.setHeader("Content-Type", contentType);
    }

    OutputStream output = response.getOutputStream();

    IOUtils.copy(inputStream, output);

    output.flush();
    output.close();
}

由于您是从一个URL读取,因此应该从该URL的
Content length
标题中获得可用的长度

HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.connect();
if ( connection.getResponseCode() == 200 ) {
    int contentLength = connection.getContentLength();
    response.setContentLength( contentLength );
请注意,您不应使用
inputStream.available()
available()
方法只告诉您可以在不阻塞的情况下读取多少字节(即等待下一个数据块从网络到达)。它不会告诉你流的大小!但是在
HttpURLConnection
中,可以使用
getContentLength()
方法获取内容长度头的值

一旦这样做,就可以启动读写循环来复制所有数据,例如

InputStream source = connection.getInputStream();
OutputStream target = response.getOutputStream();

int FILE_CHUNK_SIZE = 1024 * 4;
byte[] chunk = new byte[FILE_CHUNK_SIZE]; 
int n =0;
while ( (n = source.read(chunk)) != -1 ) {
    target.write(chunk, 0, n);
}

请记住使用try-catch解决所有这些问题,因为在这样的事务中可能会抛出多种异常。当您捕获到异常时,请记住在响应中设置一个响应代码,该代码不是200。

因为您是从URL读取的,所以您应该从该URL的
内容长度
标题中获得长度

HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.connect();
if ( connection.getResponseCode() == 200 ) {
    int contentLength = connection.getContentLength();
    response.setContentLength( contentLength );
请注意,您不应使用
inputStream.available()
available()
方法只告诉您可以在不阻塞的情况下读取多少字节(即等待下一个数据块从网络到达)。它不会告诉你流的大小!但是在
HttpURLConnection
中,可以使用
getContentLength()
方法获取内容长度头的值

一旦这样做,就可以启动读写循环来复制所有数据,例如

InputStream source = connection.getInputStream();
OutputStream target = response.getOutputStream();

int FILE_CHUNK_SIZE = 1024 * 4;
byte[] chunk = new byte[FILE_CHUNK_SIZE]; 
int n =0;
while ( (n = source.read(chunk)) != -1 ) {
    target.write(chunk, 0, n);
}

请记住使用try-catch解决所有这些问题,因为在这样的事务中可能会抛出多种异常。当您捕获到异常时,请记住在响应中设置一个响应代码,该代码不是200。

在请求对象的数据用完之前,您没有理由无法从该对象读取输入流——将其缓冲到内存中。事实上,根据我的经验,事情总是这样;我可以用一只手的手指数出我看到输入流被写入文件而不是被缓冲到内存中的次数。如果你得到一个内容长度的标题,你可以把它作为一个起点,但我不会依赖它。您需要防止输入过多,因为您不知道输入流的远端是什么,因此他们可能会向您联系的服务器发送太多的资料,导致您的RAM不足,无法处理这些资料


一直调用read()直到得到-1。其他读取方法也可以用于此目的,但您将添加更多逻辑来检测文件结尾。

在请求对象的数据用完之前,您没有理由无法从请求对象读取输入流——将其缓冲到内存中。事实上,根据我的经验,事情总是这样;我可以用一只手的手指数出我看到输入流被写入文件而不是被缓冲到内存中的次数。如果你得到一个内容长度的标题,你可以把它作为一个起点,但我不会依赖它。您需要防止输入过多,因为您不知道输入流的远端是什么,因此他们可能会向您联系的服务器发送太多的资料,导致您的RAM不足,无法处理这些资料


一直调用read()直到得到-1。其他读取方法也可用于此目的,但您将添加更多逻辑来检测文件结尾。

文件长度与您从服务器读取的内容长度不同?相同。但是调用inputStream.available()不会返回文件的实际长度,并且在将数据写入OutputStream后调用response.setHeader(“Content length”,length)不起作用。文件的长度与从服务器读取的内容长度不同?是相同的。但是调用inputStream.available()不会返回文件的实际长度,在将数据写入OutputStream后调用response.setHeader(“Content length”,length)不起作用。我已经尝试过了,但在从InputStream读取所有数据之后,设置响应的Content-Length标头就不起作用了;例如,通过读取请求的所有数据来更改请求,应该不会影响响应。我已经尝试过了,但在从InputStream读取所有数据后,设置响应的Content Length标头不起作用。这很奇怪——响应和请求是分开的对象;例如,通过读取请求的所有数据来更改请求,不应影响响应。如果未设置响应内容长度,则可能会遇到问题。这可能取决于客户端对响应的管理。如果未设置响应内容长度,则可能会遇到问题。这是可能的,这取决于客户端对响应的管理。