-1

package soundcliptest;

// development environment(NetBeans 8.0)
//
// NetBeansProjects
//     SoundClipTest
//         Source Packages
//             resources
//                ding.wav
//             soundcliptest
//                SoundClipTest.java
//

// unZipped jar file
//
// SoundClipTest
//    META-INF
//    resourses
//        ding.wav
//    soudcliptest
//        SoundClipTest.class
//

I'm still learning how to use this tool, folks. I can't seem to get the imports where they belong.

I need to know how to look into the jar file from the code. The File methods can't crack it. There must be some way of finding the contents of a resource 'directory'. What I want to do is make a menu of the sound files under /resources/. I can make it work in the development environment,, but not from the jar file. Maybe some 'zip' methods? But I haven't found them. Thanks in advance.

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.io.*;
import java.net.URL;
import javax.sound.sampled.*;
import javax.swing.*;
import javax.swing.border.BevelBorder;

public class SoundClipTest extends JFrame {

    JTextPane myPane;
    String title;
    String showIt;

    public SoundClipTest() {

        // get something to write on
        this.myPane = new JTextPane();
        this.myPane.setPreferredSize(new Dimension(700, 100));
        this.myPane.setBorder(new BevelBorder(BevelBorder.LOWERED));

        try {
            // Open an audio input stream.
            URL dingUrl = getClass().getResource("/resources/ding.wav");

            // show the path we got
            String path = dingUrl.getPath();

            //trim 'ding.wav' from file path to get a directory path
            String dirPath = path.substring(0, path.length()-"ding.wav".length());

            // now get a Url for the dir from getResource and show THAT path
            URL dirUrl = getClass().getResource("/resources/");
            String urlPath = dirUrl.getPath();

            // the dirUrl path is just like the trimmed 'ding' file path
            // so use  urlPath to get a file object for the directory
            try {
                File f = new File(urlPath);  //works fine in dev environment
                String filePath = f.getPath();  // but not from jar file
                title = f.list()[0]; // from jar, null pointer exception here

                // whan things go right (HA HA) we display this
                showIt = ("                >>>>> IT WORKED!! <<<<<!" 
                        + "\n path to file:        "+ path 
                        + "\n path to dir:        " + dirPath 
                        + "\n path from URL: " +  urlPath  
                        + "\n path from file:  "+ filePath + "\n " + title);

            } catch (Exception e) {
                // you get this on display when executing the jar file
                showIt = ("          PHOOEY"
                        + "\n the ding  " + path 
                        + "\n trimmed path " + dirPath 
                        + "\n the URL path " + urlPath 
                        + "\n could not create a File object from path");

                 // the stack trace shows up only if you run from the terminal
               e.printStackTrace();
            }

            // We get a nice little 'ding', anyway
            AudioInputStream ais = AudioSystem.getAudioInputStream(dingUrl);
            Clip clip = AudioSystem.getClip();
            clip.open(ais);
            clip.start();

            //but nuttin else good -  show the disapointing results
            myPane.setText(showIt);

        } catch (UnsupportedAudioFileException | LineUnavailableException | IOException e) {
            e.printStackTrace();
        } catch (NullPointerException e) {
            System.out.println("Ouch!!! Damn, that hurt!");
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        SoundClipTest me = new SoundClipTest();
        JFrame frame = new JFrame("Sound Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(me.myPane, BorderLayout.CENTER);
        frame.pack();
        frame.setVisible(true);
    }
}
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
  • Hmmm... Is there someplace I can find an explanation of how ti use this tool? Or do I just keep on experimenting. Guess I can figure it out on my own if I have to. – user3625050 May 13 '14 at 20:14

2 Answers2

0

OK, not a full answer but since that part is not very well documented (Oracle's page on it is obsolete), here is how to use a ZIP FileSystem over a jar file:

final Path pathToJar = Paths.get(...).toRealPath();
final String jarURL = "jar:file:" + pathToJar;
final Map<String, String> env = new HashMap<>();

final FileSystem jarfs = FileSystems.newFileSystem(URI.create(jarURL), env);

final Path rootPath = jarfs.getPath("/resources");

Then you can use Files.newDirectoryStream() over rootPath to get a list of files inside a "directory" within the jar. If you want to list recursively, use Files.walkFileTree() and write your own FileVisitor (most of the time, extending SimpleFileVisitor is enough).

NOTE: a FileSystem implements Closeable; you should ensure to .close() it once you're done with it. And so does a DirectoryStream for that matter.

fge
  • 119,121
  • 33
  • 254
  • 329
0

Caveat Emptor

This is assuming that you have not fiddled with classloaders, this will work with the URLClassLoader but is an implementation detail of that class, not part of the public API.

If you load a classpath directory resource then you will get a line for each resource in that directory.

Lets assume you have this structure:

/resources
    /test1.txt
    /test2.txt

If we do the following:

try (final Scanner scanner = new Scanner(getClass().getResourceAsStream("/resources"))) {
    while (scanner.hasNextLine()) {
        final String line = scanner.nextLine();
        System.out.println(line);
    }
}

This will output:

test1.txt
test2.txt

So you can use this to return a list of names of files:

List<String> readClassPath(final String root) {
    final List<String> resources = new LinkedList<>();
    try (final Scanner scanner = new Scanner(getClass().getResourceAsStream(root))) {
        while (scanner.hasNextLine()) {
            final String line = scanner.nextLine();
            System.out.println(line);
            resources.add(root + "/" + line);
        }
    }
    return resources;
}

This returns:

[/resources/test1.txt, /resources/test2.txt]
Boris the Spider
  • 59,842
  • 6
  • 106
  • 166