代码之家  ›  专栏  ›  技术社区  ›  Grumblesaurus

更有效地从JAR中提取文件

  •  2
  • Grumblesaurus  · 技术社区  · 15 年前

    我正在扩展一个实用程序类,它捆绑了一组图像和.xml描述文件。目前,我将所有文件保存在一个目录中,并从那里加载它们。目录如下:

    8.png
    8.xml
    9.png
    9.xml
    10.png
    10.xml
    ...
    ...
    50.png
    50.xml
    ...
    



    这是我当前的构造函数。它闪电般的快,做我需要它做的事。(我去掉了一些错误检查,以便更容易阅读):

    public DivineFont(String directory ) {
    
        File dir = new File(directory);
    
        //children is an array that looks like this: '10.fnt', '11.fnt', etc.
        String[] children = dir.list(fntFileFilter);
    
        fonts = new Hashtable<Integer, AngelCodeFont>(100);
    
        AngelCodeFont buffer;
        int number;
                String fntFile;
                String imgFile;
    
        for(int k = 0; k < children.length; k++ ) {
            number = Integer.parseInt( children[k].split("\\.")[0] );
            fntFile = directory + File.separator + number + ".xml";
            imgFile = directory + File.separator + number + ".png";
            buffer = new AngelCodeFont(fntFile, imgFile);
    
            fonts.put(number, buffer);
        }
    }
    

    为了WebStart和清洁,我尝试从一个jar加载这些资源。我已经让它工作了,但是加载时间从瞬间变为几秒钟,这是不可接受的。这是我尝试的代码(再次,去掉错误检查):

    (这不是 最好的 做我想做的事情,这是一个模型,看看这个想法是否有效。它没有。两个for循环决不是问题的根源;它是创建所有这些输入流的过程,减慢了速度)

    public DivineFont(String jarFileName ) {
    
        JarFile jarfile = new JarFile(jarFileName);
        Enumeration<JarEntry> em = jarfile.entries();
        ArrayList<Integer> fontHeights = new ArrayList<Integer>(100);
        for (Enumeration em1 = jarfile.entries(); em1.hasMoreElements(); ) {
            String fileName = em1.nextElement().toString();
            if( fileName.endsWith(".fnt") ) {
                fontHeights.add( Integer.parseInt(fileName.split("\\.")[0] ) );
            }
        }
    
        fonts = new Hashtable<Integer, AngelCodeFont>(100);
    
        AngelCodeFont buffer;
        int number;
    
        for(int k = 0; k < fontHeights.size(); k++ ) {
            number = fontHeights.get(k);
            InputStream fntFileStream = jarfile.getInputStream(jarfile.getEntry(number + ".xml"));
            InputStream pngFileStream = jarfile.getInputStream(jarfile.getEntry(number + ".png"));
            buffer = new AngelCodeFont(String.valueOf(number), fntFileStream, pngFileStream );
    
            fonts.put(number, buffer);
    
    
        }
    }
    


    除了我在这里的尝试之外,还有谁知道更好的处理.jar文件的方法?这里是 AngelCodeFont API . 如果这是绝对必要的,我可以提交一个补丁,但我宁愿不必。在我看来,可能有一种方法可以做我想做的事情,我只是不熟悉它。

    我并不反对快速地将jar转储到一个临时目录,然后从那里读取文件,但是如果有一种方法可以快速地直接从jar读取,我宁愿这样做。

    另外:压缩根本不是问题。我使用罐子的唯一原因是包装问题。

    4 回复  |  直到 15 年前
        1
  •  4
  •   Aaron Digulla    15 年前

    开口 罐子是一种非常昂贵的操作。所以你可能想打开罐子一次,然后 JarFile 实例在某个静态字段中。在您的情况下,您还需要读取所有条目并将它们保存在哈希图中,以便即时访问所需的资源。

    另一种解决方案是将jar放在类路径上并使用

    DivineFont.class.getContextClassLoader().getResource*("/8.png");
    

    注意“/”!如果省略它,Java将在找到文件DivineFont.class的同一目录(包)中搜索。

    从类路径中获取东西已经在Java中被优化为死亡。

        2
  •  1
  •   Grumblesaurus    15 年前

    嗯,我找到了答案。原始问题的答案是“错误的问题”。JAR文件不是问题所在,而是我用来加载图像的库。

    当我从文件系统加载时,图像被命名为“38.png”等。当我从jar加载时,我只是将它命名为“38”。

    库中的图像加载器类使用名称的文件扩展名来标识要使用的图像加载器。如果没有文件扩展名,则使用较慢的基本图像加载器。当我更改此行时:

    buffer = new AngelCodeFont(String.valueOf(number), fntFileStream, pngFileStream );
    

    这条线:

    buffer = new AngelCodeFont( number + ".png", fntFileStream, pngFileStream );
    

    我们自己就是赢家。

    不管怎样,谢谢你们的帮助。我花了几个小时才明白这一点,但如果不是你的帖子,我可能会继续认为是Java而不是我正在使用的图书馆。

        3
  •  0
  •   Jared    15 年前

    JAR文件操作可能非常昂贵,Java类库已经实现了这种资源加载(可能是尽可能高效的)。

    另外,一旦你进入webstart,你的jar文件名就会被破坏,所以你可能最终不得不探索类路径上的每个jar文件来加载你的资源(我已经做到了!难看!)

    相反,使用 Class.getResourceAsStream(String resourceName) . 我没有对它进行分析,但是我没有注意到它比直接文件访问慢得多。

        4
  •  -2
  •   leeand00    15 年前

    This library 可能不会压缩到你需要的程度,但会更快…