【问题标题】:Fastest way to read/write Images from a File into a BufferedImage?将文件中的图像读/写到 BufferedImage 的最快方法?
【发布时间】:2013-09-02 13:30:38
【问题描述】:
  1. 在 Java/Grails 中将图像从文件读取到 BufferedImage 的最快方法是什么?
  2. 在 Java/Grails 中将图像从 BufferedImage 写入文件的最快方法是什么?

我的变种(阅读):

byte [] imageByteArray = new File(basePath+imageSource).readBytes()
InputStream inStream = new ByteArrayInputStream(imageByteArray)
BufferedImage bufferedImage = ImageIO.read(inStream)

我的变种(写):

BufferedImage bufferedImage = // some image
def fullPath = // image page + file name
byte [] currentImage

try{

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ImageIO.write( bufferedImage, "jpg", baos );
    baos.flush();
    currentImage = baos.toByteArray();
    baos.close();

    }catch(IOException e){
        System.out.println(e.getMessage());
    }       
   }    


def newFile = new FileOutputStream(fullPath)
newFile.write(currentImage)
newFile.close()

【问题讨论】:

    标签: java grails grails-2.0 javax.imageio


    【解决方案1】:

    您的读取解决方案基本上是两次读取字节,一次从文件中读取,一次从ByteArrayInputStream 读取。不要那样做

    使用 Java 7 阅读

    BufferedImage bufferedImage = ImageIO.read(Files.newInputStream(Paths.get(basePath + imageSource)));
    

    用Java 7来写

    ImageIO.write(bufferedImage, "jpg", Files.newOutputStream(Paths.get(fullPath)));
    

    Files.newInputStream 的调用将返回一个ChannelInputStream,它(AFAIK)没有被缓冲。你会想要包装它

    new BufferedInputStream(Files.newInputStream(...));
    

    这样就可以减少对磁盘的 IO 调用,具体取决于您使用它的方式。

    【讨论】:

    • 我读到 Java Toolkit 的阅读速度非常快,不是吗?如果这是真的,你能修改你的答案吗?
    • @stephan1001 对不起,我对UI相关的包不熟悉。
    • @stephan1001 这些是 Java 7 类。包是java.nio.file.Filesjava.nio.file.Paths
    • @stephan1001 一个无缓冲的FileInputStream 将进行大量的 IO OS 调用以从磁盘读取。通过缓冲,您读取的内容超出了您的需要,从而减少了对磁盘的调用。在这种情况下,这是有道理的,因为无论如何您最终都会读取整个文件。
    • @stephan1001 使用对应的BufferedOutputStream 方法相同。
    【解决方案2】:

    我迟到了,但无论如何......

    实际上,使用:

    ImageIO.read(new File(basePath + imageSource));
    

    ImageIO.write(bufferedImage, "jpeg", new File(fullPath));
    

    ...可能会更快(尝试一下,使用分析器,以确保)。

    这是因为这些变体在后台使用RandomAccessFile-backed ImageInputStream/ImageOutputStream 实现,而基于InputStream/OutputStream 的版本将默认使用磁盘支持的可搜索流实现。磁盘备份涉及将流的全部内容写入临时文件,并可能从中读取(这是因为图像 I/O 通常受益于非线性数据访问)。

    如果您想在基于流的版本中避免额外的 I/O,以使用更多内存为代价,可以调用模糊命名的 ImageIO.setUseCache(false),以禁用 磁盘缓存可搜索的输入流。如果您正在处理非常大的图像,这显然不是一个好主意。

    【讨论】:

    • 所以这个版本 ImageIO.read(new File(basePath + imageSource));比 ImageIO.read(new BufferedInputStream(Files.newInputStream(Paths.get(basePath + imageSource)))) 快这是真的吗?
    • @stephan1001 理论上是的(假设默认设置为useCahce false)。但正如我所说,测量以确保。 :-)
    • 为了它,我写了一个示例程序,它使用文件版本、流版本和没有磁盘缓存的流版本读取一个中等大小的 JPEG 100 次。时间是平均时间。使用文件的时间:36.76ms 使用流的时间:40.32ms 使用流的时间(useCache==false):37.63ms JDK 1.6.0_26-b03-383 on OS X, 2.66GHz i7 + SSD。您的里程可能会有所不同...
    • 使用 BufferedImages 的 ImageIO 读写是否会改变图像质量?
    • 问题是:当我将 jpg 图像加载到 BufferedImage 并将其从 BufferedImage 保存回 jpg 文件时,这会导致质量损失吗?
    【解决方案3】:

    你几乎擅长写作。只是不要使用中间的 ByteArrayOutputStream。这是您代码中的一个巨大瓶颈。而是将 FileOutputStream 包装在 BufferedOutputStream 中并执行相同操作。

    你的阅读也是如此。移除 Itermediate ByteArrayInputStream。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-17
      相关资源
      最近更新 更多