更有效地从Jar中提取文件

时间:2009-02-12 16:24:28

标签: java jar compression zip

我正在扩展一个实用程序类,它捆绑了一组图像和.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循环在不是问题的根源;它是创建所有那些减慢它的InputStreams的过程)

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 个答案:

答案 0 :(得分:4)

打开 JAR是一项非常昂贵的操作。因此,您可能希望打开JAR一次,并将JarFile实例保存在某个静态字段中。在您的情况下,您还需要读取所有条目并将它们保存在哈希映射中,以便即时访问所需的资源。

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

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

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

从类路径中获取内容已经在Java中优化为死亡。

答案 1 :(得分:1)

好吧,我找到了答案。我原来问题的答案是“错误的问题”。 Jar文件不是问题,它是我用来加载图像的库。

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

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

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

到这一行:

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

我们自己是胜利者。

无论如何,谢谢你的帮助。我花了几个小时才弄清楚这一点,但如果不是你的帖子,我可能会继续认为责任是Java而不是我正在使用的图书馆。

答案 2 :(得分:0)

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

另外,一旦你进入webstart,你的jar文件名就会被破坏,所以你最终可能不得不浏览类路径上的每个jar文件来加载你的资源(我已经完成了!很丑!)

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

答案 3 :(得分:-2)

This library可能无法根据需要进行压缩,但会更快......