Java ImageIO.read(…)-速度很慢,有更好的方法吗?

Java ImageIO.read(…)-速度很慢,有更好的方法吗?,java,Java,我正在加载大量图标,这些图标将在我的应用程序中使用。我计划在服务器启动时从jar加载所有这些文件。然而,数百张图像加起来刚刚超过9MB,执行此任务仍需30秒以上。我现在是在一个单独的线程中完成的,但这让我怀疑我在代码中是否做了一些效率低下的事情。我借用了SO的代码将信息加载到我的结构中。我将代码放入测试类并对其进行了分析。99%的配置文件使用ImageIO.read(..)方法。所以这绝对是瓶颈。下面是一个测试类,它应该提供关于我如何使用ImageIO的图片 public class IconT

我正在加载大量图标,这些图标将在我的应用程序中使用。我计划在服务器启动时从jar加载所有这些文件。然而,数百张图像加起来刚刚超过9MB,执行此任务仍需30秒以上。我现在是在一个单独的线程中完成的,但这让我怀疑我在代码中是否做了一些效率低下的事情。我借用了SO的代码将信息加载到我的结构中。我将代码放入测试类并对其进行了分析。99%的配置文件使用ImageIO.read(..)方法。所以这绝对是瓶颈。下面是一个测试类,它应该提供关于我如何使用ImageIO的图片

public class IconTest {

/**
 * @param args the command line arguments
 * @throws java.net.URISyntaxException
 * @throws java.io.IOException
 */
public static void main(String[] args) throws URISyntaxException, IOException {
    URI uri = IconTest.class.getResource("Icons").toURI();
    Path myPath;
    if (uri.getScheme().equals("jar")) {
        FileSystem fileSystem = FileSystems.newFileSystem(uri, Collections.<String, Object>emptyMap());
        myPath = fileSystem.getPath("Icons/");
    } else {
        myPath = Paths.get(uri);
    }
    IconFolder root = new IconFolder(myPath.toFile().getName());
    IconFolder parentFolder = root;
    HIcon currentIcon = null;
    IconFolder folder = null;
    HashMap<String,IconFolder> folders = new HashMap<>();
    folders.put(parentFolder.getName(), parentFolder);
    Stream<Path> walk = Files.walk(myPath, 5);
    Iterator<Path> it = walk.iterator();it.next();
    while(it.hasNext()){
        Path path = it.next();
        if(path.toFile().isDirectory()){
            folder = new IconFolder(path.toFile().getName());
            folders.put(folder.getName(), folder);
            String parentName = path.getParent().toFile().getName();
            parentFolder = folders.get(parentName);
            parentFolder.addSubFolder(folder);
            currentIcon =null;
            System.out.println("Directory: " + path);
        }else{
            URL url = path.toUri().toURL();

            ImageIcon icon = new ImageIcon(ImageIO.read(url));
            //Image image = Toolkit.getDefaultToolkit().getImage(url);
            //ImageIcon icon = new ImageIcon(image);
            String[] iconName;
            iconName = path.getFileName().toString().replaceAll("_000000", "").replaceAll(".png","").split("_",2);
            String imageName = iconName[0];
            String imageSize = iconName[1];
            if(currentIcon==null||!currentIcon.getName().equals(imageName)){
                currentIcon = new HIcon(imageName);
                folder.addIcon(currentIcon);
                currentIcon.setIcon(icon, imageSize );
            }else{
                currentIcon.setIcon(icon, imageSize);
            }
            //System.out.println("Image: " + imageName+"-->"+imageSize);
        }
    }
    System.out.println("");
}
}
公共类IconTest{
/**
*@param指定命令行参数
*@throws java.net.URISyntaxException
*@抛出java.io.IOException
*/
公共静态void main(字符串[]args)抛出URISyntaxException、IOException{
URI=IconTest.class.getResource(“Icons”).toURI();
路径myPath;
if(uri.getScheme().equals(“jar”)){
FileSystem FileSystem=FileSystems.newFileSystem(uri,Collections.emptyMap());
myPath=fileSystem.getPath(“Icons/”);
}否则{
myPath=path.get(uri);
}
IconFolder root=新的IconFolder(myPath.toFile().getName());
iconfolderparentfolder=根目录;
HIcon currentIcon=null;
IconFolder文件夹=null;
HashMap folders=新建HashMap();
folders.put(parentFolder.getName(),parentFolder);
streamwalk=Files.walk(myPath,5);
迭代器it=walk.Iterator();it.next();
while(it.hasNext()){
Path=it.next();
if(path.toFile().isDirectory()){
folder=newiconfolder(path.toFile().getName());
folders.put(folder.getName(),folder);
字符串parentName=path.getParent().toFile().getName();
parentFolder=folders.get(parentName);
parentFolder.addSubFolder(文件夹);
currentIcon=null;
System.out.println(“目录:+path”);
}否则{
URL=path.toUri().toURL();
ImageIcon图标=新的ImageIcon(ImageIO.read(url));
//Image Image=Toolkit.getDefaultToolkit().getImage(url);
//ImageIcon图标=新的ImageIcon(图像);
字符串[]图标名;
iconName=path.getFileName().toString().replaceAll(“.000000”).replaceAll(“.png”).split(“.u000000”),2);
字符串imageName=iconName[0];
字符串imageSize=iconName[1];
如果(currentIcon==null | |!currentIcon.getName().equals(imageName)){
currentIcon=新HIcon(图像名称);
文件夹.addIcon(当前图标);
currentIcon.setIcon(图标,图像大小);
}否则{
currentIcon.setIcon(图标,图像大小);
}
//System.out.println(“图像:“+imageName+”-->“+imageSize”);
}
}
System.out.println(“”);
}
}
任何指示都会有帮助。我看了一些我认为是在指出同样的事情的SO帖子。我正在使用带SSD的MacBook Air,所以我认为这会是闪电般的快

我在下面添加了个人资料结果的屏幕截图:

这是将
setUseCache
设置为false后的配置文件:


您可以尝试使用
ImageIO.setUseCache(false)
来使用基于内存的缓存而不是基于磁盘的缓存(因为它是默认的)


参考资料:

我终于找到了一个解决办法。以下为最新资料:

这是一个非常有趣的解决方案。我决定使用一个执行器,以便读取操作可以并行化。我已经为运行整个任务创建了一个线程,但将其分解为更细粒度的任务确实加快了速度

最后,我把这个时间从38.9秒降到了3.4秒。这是我书中的一大收获。这对我来说很重要,因为我希望我的服务器尽快启动,而且我绝对不想失去39秒的启动时间

我选择将它硬编码为5个线程,因为我在mac上开发,它只有4个内核。我尝试了15个或以上的核心+1,它会失去效率

以下是调整后的示例代码:

public class IconTest {

/**
 * @param args the command line arguments
 * @throws java.net.URISyntaxException
 * @throws java.io.IOException
 */
public static void main(String[] args) throws URISyntaxException, IOException {
    test4();
}

public static void test4() throws MalformedURLException, IOException, URISyntaxException{
    ExecutorService service = Executors.newFixedThreadPool(5);
    URI uri = IconTest.class.getResource("../resources/Icons").toURI();
    Path myPath;
    if (uri.getScheme().equals("jar")) {
        FileSystem fileSystem = FileSystems.newFileSystem(uri, Collections.<String, Object>emptyMap());
        myPath = fileSystem.getPath("Icons/");
    } else {
        myPath = Paths.get(uri);
    }
    IconFolder root = new IconFolder(myPath.toFile().getName());
    IconFolder parentFolder = root;
    HIcon currentIcon = null;
    IconFolder folder = null;
    HashMap<String,IconFolder> folders = new HashMap<>();
    folders.put(parentFolder.getName(), parentFolder);
    Stream<Path> walk = Files.walk(myPath, 10);
    Iterator<Path> it = walk.iterator();it.next();
    Info.Info("Starting loading icons....");
    ImageIO.setUseCache(false);
    while(it.hasNext()){
        Path path = it.next();
        if(path.toFile().isDirectory()){
            folder = new IconFolder(path.toFile().getName());
            folders.put(folder.getName(), folder);
            String parentName = path.getParent().toFile().getName();
            parentFolder = folders.get(parentName);
            parentFolder.addSubFolder(folder);
            currentIcon =null;
            Info.Info("Directory: " + path);
        }else{
            ImageLoadingTask task;
            URL url = path.toUri().toURL();
            String[] iconName;
            iconName = path.getFileName().toString().replaceAll("_000000", "").replaceAll(".png","").split("_",2);
            String imageName = iconName[0];
            String imageSize = iconName[1];
            if(currentIcon==null||!currentIcon.getName().equals(imageName)){
                currentIcon = new HIcon(imageName);
                folder.addIcon(currentIcon);
                task = new ImageLoadingTask(url,currentIcon,imageSize);
                service.submit(task);
            }else{
                task = new ImageLoadingTask(url,currentIcon,imageSize);
                service.submit(task);
            }
            //Info.Info("Image: " + imageName+"-->"+imageSize);
        }
    }
    service.shutdown();
    Info.Info("Finished loading icons....");
}

static public class ImageLoadingTask implements Callable<ImageIcon> {

    private final URL url;
    private final HIcon hIcon;
    private final String size;

    public ImageLoadingTask(URL url, HIcon hIcon, String size ) {
        this.url = url;
        this.hIcon=hIcon;
        this.size=size;
    }

    @Override
    public ImageIcon call() throws Exception {
        ImageIcon icon = new ImageIcon(ImageIO.read(url));
        hIcon.setIcon(icon, size);
        return icon;
    }
}
}
公共类IconTest{
/**
*@param指定命令行参数
*@throws java.net.URISyntaxException
*@抛出java.io.IOException
*/
公共静态void main(字符串[]args)抛出URISyntaxException、IOException{
test4();
}
public static void test4()引发畸形的DurLexception、IOException、URISyntaxException{
ExecutorService=Executors.newFixedThreadPool(5);
URI=IconTest.class.getResource(“../resources/Icons”).toURI();
路径myPath;
if(uri.getScheme().equals(“jar”)){
FileSystem FileSystem=FileSystems.newFileSystem(uri,Collections.emptyMap());
myPath=fileSystem.getPath(“Icons/”);
}否则{
myPath=path.get(uri);
}
IconFolder root=新的IconFolder(myPath.toFile().getName());
iconfolderparentfolder=根目录;
HIcon currentIcon=null;
IconFolder文件夹=null;
HashMap folders=新建HashMap();
folders.put(parentFolder.getName(),parentFolder);
streamwalk=Files.walk(myPath,10);
迭代器it=walk.Iterator();it.next();
Info.Info(“开始加载图标…”);
ImageIO.setUseCache(false);
while(it.hasNext()){
Path=it.next();
if(path.toFile().isDirectory()){
folder=newiconfolder(path.toFile().getName());
folders.put(folder.getName(),folder);
字符串parentName=path.getParent().toFile().getName();
parentFolder=folders.get(parentName);
parentFolder.addSubFolder(文件夹);
currentIcon=null;
Info.Info(“目录:+路径”);
}否则{
图像加载任务;
URL=path.toUri().toURL();