如何提高BufferedInputStream的转换速度?

小弟对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();
}
阅读 1k
avatarAI BotBETA

要提高 BufferedInputStream 的转换速度,并优化图片加载过程,你可以考虑以下几个方向:

  1. 增加缓冲区大小
    当前你使用的缓冲区大小为 1024 字节(1KB)。对于较大的文件(如5MB的图片),增加缓冲区大小可以显著减少读写操作的次数,从而提高效率。例如,可以将缓冲区大小增加到 8192 字节(8KB)或更大,这取决于你的系统内存和可用资源。
  2. 使用更高效的流处理
    虽然 BufferedInputStream 已经是对输入流的一种缓冲封装,但在处理大文件时,你还可以考虑使用更高级的库,如 Apache Commons IO 的 IOUtils,它提供了更简洁的流操作方法,并且可能内部优化了流处理。
  3. 并发处理
    如果你的应用场景允许,并且服务器有足够的资源,可以考虑使用并发或异步处理来加速图片加载。例如,可以使用 Java 的 ExecutorService 来管理多个线程,每个线程处理不同的图片下载和加载任务。
  4. 网络优化
    检查网络连接是否稳定且高效。有时,网络延迟或带宽限制可能是影响图片加载速度的主要因素。
  5. 服务器和客户端缓存
    对于频繁访问的图片,考虑在服务器或客户端实现缓存机制,以减少重复下载的需要。
  6. 代码优化
    确保 response.getOutputStream() 的调用和设置响应类型等操作不会阻塞或影响主要的数据处理流程。

以下是针对你的代码,增加缓冲区大小后的示例:

try {
    URL url = new URL(imageUrl);
    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
    connection.setRequestMethod("GET");
    connection.setConnectTimeout(5000);
    BufferedInputStream bis = new BufferedInputStream(connection.getInputStream(), 8192); // 增加缓冲区大小
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte[] buffer = new byte[8192]; // 相应地增加缓冲区大小
    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 个回答
✓ 已被采纳

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

  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();
    }
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏