如何提高BufferedInputStream的转换速度?

作者站长头像
站长
· 阅读数 11

小弟对io流很陌生,请问大佬下面的代码怎么优化?图片5Mb的时候要等8sm,怎么提高加载速度?

try {
    URL url = new URL(imageUrl);
    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
    connection.setRequestMethod("GET");
    connection.setConnectTimeout(5000);
    BufferedInputStream bis = new BufferedInputStream(connection.getInputStream());
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024];
    int len;
    while ((len = bis.read(buffer)) != -1) {
        baos.write(buffer, 0, len);
    }
    OutputStream outputStream = response.getOutputStream();
    response.setContentType("image/jpg");
    outputStream.write(baos.toByteArray());
    outputStream.flush();
    outputStream.close();
} catch (Exception e) {
    e.printStackTrace();
}
回复
1个回答
avatar
test
2024-08-11

你的问题主要有这么几处:

  1. 从HTTP读取到的数据,等待全部读取完放在了内存中,等待耗时,文件很大并发时可能会内存溢出
  2. 阻塞读取,将数据全部存buffer过程中,response一直在等待,什么也没做,可以边读边写
  3. HTTP请求连接未复用,建议使用OK-http等库复用连接
  4. 资源未释放,response会等待超时,且内存会泄露

方案1:原始流复制,这里的buffer越大,效率越快,但是注意内存占用

HttpURLConnection connection = null;
try {
    URL url = new URL(imageUrl);
    connection = (HttpURLConnection) url.openConnection();
    connection.setRequestMethod("GET");
    connection.setConnectTimeout(5000);
    try(InputStream bis = new BufferedInputStream(connection.getInputStream());
        OutputStream out = response.getOutputStream()) {
        response.setContentType("image/jpg");
        
        // buffer 越大,效率越快
        byte[] buffer = new byte[1024];
        int len;
        while ((len = bis.read(buffer)) != -1) {
            out.write(buffer, 0, len);
            
            out.flush();
            
        }
    }
} catch (Exception e) {
    throw new RuntimeException(e);
} finally {
    if(null != connection){
        connection.disconnect();
    }
}

方案2:使用一些三方库的COPY工具类

HttpURLConnection connection = null;
try {
    URL url = new URL(imageUrl);
    connection = (HttpURLConnection) url.openConnection();
    connection.setRequestMethod("GET");
    connection.setConnectTimeout(5000);
    try(InputStream bis = new BufferedInputStream(connection.getInputStream());
        OutputStream out = response.getOutputStream()) {
        response.setContentType("image/jpg");

        IoUtil.copy(bis, out);
        
    }
} catch (Exception e) {
    throw new RuntimeException(e);
} finally {
    if(null != connection){
        connection.disconnect();
    }
}

方案3:使用NIO非阻塞传输,同样缓冲区越大,效率越快

HttpURLConnection connection = null;
try {
    URL url = new URL(imageUrl);
    connection = (HttpURLConnection) url.openConnection();
    connection.setRequestMethod("GET");
    connection.setConnectTimeout(5000);
    try (ReadableByteChannel in = Channels.newChannel(new BufferedInputStream(connection.getInputStream()));
         WritableByteChannel out = Channels.newChannel(response.getOutputStream())) {
        response.setContentType("image/jpg");

        ByteBuffer byteBuffer = ByteBuffer.allocate(8192);
        while (in.read(byteBuffer) != -1) {
            // 写转读
            byteBuffer.flip();
            out.write(byteBuffer);
            byteBuffer.clear();
        }
    }
} catch (Exception e) {
    throw new RuntimeException(e);
} finally {
    if (null != connection) {
        connection.disconnect();
    }
}
回复
likes
适合作为回答的
  • 经过验证的有效解决办法
  • 自己的经验指引,对解决问题有帮助
  • 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
  • 询问内容细节或回复楼层
  • 与题目无关的内容
  • “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容