在JAR中访问Java资源会返回大约75%的垃圾

时间:2017-06-02 20:05:30

标签: java jar classloader embedded-resource

我试图在我的JAR文件中加载WAV资源文件。它通过IDE运行时非常有效。但是当通过java -jar运行时,它给了我大约75%的垃圾和25%的正确数据。我想知道为什么。以下是我尝试的一些方法:

  1. (我的首选方法):使用JAR中的getResourceAsStream读取包含原始部分内容的损坏数据:

    short[] waveform = AudioFileAPI.readWavFile(
        Blah.class.getResourceAsStream("/blah.wav"));
    
  2. 从常规文件中读取:确定

    waveform = AudioFileAPI.readWavFile(new File("C:\\blah\\blah.wav"));
    
  3. 从创建的JAR中提取wav并将其作为常规文件读取:确定

    waveform = AudioFileAPI.readWavFile(new File("C:\\blah\\fromjar.wav"));
    
  4. 使用getResource读取并在AppletAudioClip上调用play()可以获得75%的损坏数据。

    Object o = Blah.class.getResource("/blah.wav").getContent();
    AppletAudioClip appletAudioClip = (AppletAudioClip) o;
    appletAudioClip.play();
    
  5. 通过getResource()读取.openStream():75%损坏的数据如上所述。

    InputStream is = Blah.class.getResource("/blah.wav").openStream();
    waveform = AudioFileAPI.readWavFile(is);
    
  6. 解压缩并重新压缩JAR并重新运行该程序也没有帮助。

  7. 回顾一下,从IDE运行时,所有上述方法都可以正常工作,但是当作为资源加载时,指示的方法会失败。 JAR由IntelliJ IDEA打包。我使用JDK版本1.8.0_131。 AudioFileAPI是我自己的类。

2 个答案:

答案 0 :(得分:0)

这实际上是由于正在读取资源的InputStream的代码中的错误。如果InputStream的read()方法由于某种原因没有一次性读取所有字节,则后续{{1}}次尝试将错误地写入始终从位置0开始的同一缓冲区,而不是开始在由目前读取的总字节数确定的位置。

所以,最后,缓冲区看起来像开头有正确数据的碎片,最后是垃圾。

答案 1 :(得分:0)

read()不保证一次性读取您的文件。如果您阅读InputReader的文档。它说

  

从输入流中读取一定数量的字节,并将其存储到缓冲区数组b中。

即使read(byte[] b, int off, int len)函数签名也不保证它将读取您提供的所有len字节。

  

从输入流中读取最多len个字节的数据到一个字节数组中。 尝试读取多达len个字节,但可能读取的字节数较小。实际读取的字节数以整数形式返回。

因此,您必须循环执行,直到available()为零为止。

以下是示例代码,其中还包含有关如何在jar文件中指定文件的信息。

更改jarPath以指向jarFile的位置。然后更改filePath以指向jar内的文件。 如果您的文件位于

  

someJar.jar \ img \ test.gif

将filePath设置为“ img \ test.gif”

File executable = new File(jarPath);
JarFile jar = new JarFile(executable);
InputStream fileInputStreamReader = jar.getInputStream(jar.getJarEntry(filePath));
byte[] bytes = new byte[fileInputStreamReader.available()];

int sizeOrig = fileInputStreamReader.available();
int size = fileInputStreamReader.available();
int offset = 0;
while (size != 0){
    fileInputStreamReader.read(bytes, offset, size);
    offset = sizeOrig - fileInputStreamReader.available();
    size = fileInputStreamReader.available();
}