当前位置: 首页 > 知识库问答 >
问题:

java - 如何提高BufferedInputStream的转换速度?

刘星火
2024-08-01

小弟对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();
}

共有2个答案

松高爽
2024-08-01

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

  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();
    }
}
邢皓
2024-08-01

要提高 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();
}

注意,增加缓冲区大小可能会增加内存使用量,因此需要根据实际情况调整。此外,如果图片非常大或非常多,考虑使用流式处理或分页加载等技术来减轻内存和带宽压力。

 类似资料:
  • 本文向大家介绍如何提高javascript加载速度,包括了如何提高javascript加载速度的使用技巧和注意事项,需要的朋友参考一下 方法如下: 1、将所有<script>标签放在尽可能接近<body>标签底部的位置,以保证页面在脚本运行之前完成解析尽量减少对整个页面下载的影响 2、限制页面的<script>总数也可以改善性能。每当页面解析碰到一个<script>标签时, 紧接着有一段时间用于代

  • 我是Apache Hbase的新手,我使用的是hbase-0.98.13,并且我已经创建了一个表示例,其列族为sample_family。并且我已经将pig脚本的输出加载到hbase表中。当我尝试基于列族中的一个列扫描表时,它需要超过2分钟。 是否为此进行任何配置更改?有人能帮我吗?

  • 嗨,有没有什么方法可以提高滚动速度。我找到了一些解决方案,但都不适合我。这就是我尝试的: 或者使用css: 还有别的办法吗?编辑:上面的解决方案都不起作用,我试图使用大得离谱的数字,但滚动速度还是一样

  • 我正在项目的中添加。 所有工作都很好,但在JPanel中使用鼠标滚轮滚动鼠标存在一个问题。滚动时速度很慢。如何让它更快? 我的代码是:

  • 问题内容: 嗨,我想将此BufferedInputStream放入我的字符串中,我该怎么做? 问题答案: BufferedInputStream in = new BufferedInputStream(sktClient.getInputStream()); byte[] contents = new byte[1024];

  • 问题内容: 我知道以前有一些关于文件读取,二进制数据处理和整数转换的问题,所以我来这里询问我有一段代码,我认为这花费了太多时间。所读取的文件是多通道数据样本记录(短整数),具有插入的数据间隔(因此有嵌套语句)。代码如下: 使用此代码,使用具有2Mb RAM的双核,每兆字节读取2.2秒,并且我的文件通常具有20+ Mb,这会带来一些非常令人讨厌的延迟(特别是考虑到另一个我试图镜像加载文件的基准共享软

  • 问题内容: 我有一个从java.awt.Component扩展的JPictureBox,请参见此处的代码http://pastebin.com/SAJc6Sht。但是,只有在没有图像拉伸的情况下,它才能很好地工作。特别是对于大局而言,它会极大地减慢程序速度。如何提高JPictureBox的大图绘制速度? 问题答案: 基本上,您希望将图像的缩放卸载到后台线程,缩放很耗时,并且您不想在事件调度线程的上

  • 1背景 在本文中,我们将描述如何将地图点与光栅相关联。我的问题是,如果函数st_worldtorastercoordx(rast,geom)在光栅对象中有超过10000*10000个像素,我们如何提高速度。此问题与中间件PostGIS光栅对象相关。 2 创建路测数据点对象 2.1 创建点对象字段 在前面的对象中,我们使用水壶中间件将驱动测试数据文件上传到Postgres-SQL数据库中。在数据库中