-1

My program displays elements read from a text file. The text files will be stored in a folder found in the package folder containing the .java and .class files so they can be embedded in the jar.

I'm trying to get the application to read the text files properly for both situations

  1. Running from the IDE (Netbeans)
  2. Running from the JAR

Currently I can do point one with no problem, but the code reads using File where as the way I am seeing how to do it with Jars is using InputStream.

The functions which work for the IDE runs

public void loadWidgets() {

    ArrayList<String> results = new ArrayList<>();
    String dir = new File("").getAbsolutePath() + "/src/Creator/textFiles/widgets/;
    System.out.println(dir);
    getWidgetFiles(dir, results);

    results.stream().forEach((s) -> {
        readFile(s); // given a string and it opens the file using a Scanner
    });

    updateWidgetVariables(); // gui updates
}

public void getWidgetFiles(String dirName, ArrayList<String> filePaths) {

    File directory = new File(dirName);
    File[] files = directory.listFiles();

    for (File file : files) {
        if (file.isFile()) {
            filePaths.add(file.getName() + "," + file.getAbsolutePath());
        } else if (file.isDirectory()) {
            getWidgetFiles(file.getAbsolutePath(), filePaths);
        }
    }
}

So I have a bunch of text files organized by the type of widget it is, so I am running through the /widgets/ directory to find all the text files.

The problem I'm having is how I can go through the directories and files of a Jar? Can they be converted to a file, or read into a string?

I got this code from this question and it can read the files, but I dont know how I can open them using a new Scanner(file); code

CodeSource src = WidgetPanel.class.getProtectionDomain().getCodeSource();
try {
    System.out.println("Inside try");
    List<String> list = new ArrayList<>();
    if (src != null) {
        URL jar = src.getLocation();
        ZipInputStream zip = new ZipInputStream(jar.openStream());
        ZipEntry ze = null;
        System.out.println(jar.getPath());
        System.out.println(zip.getNextEntry());

        while ((ze = zip.getNextEntry()) != null) {
            String entryName = ze.getName();
            System.out.println("Entry name: " + entryName);
            if (entryName.startsWith("Creator/textFiles/widgets") && entryName.endsWith(".txt")) {
                list.add(entryName);
                System.out.println("Added name: " + entryName);
            }
        }
        list.stream().forEach((s) -> {
            readFile(s);
        });

        updateWidgetVariables();

    } else {
        System.out.println("Src null");
    }
}catch (IOException e) {
    System.out.println(e.getMessage());
}
Community
  • 1
  • 1
Eric G
  • 928
  • 1
  • 9
  • 29
  • Which version of Java? – fge Dec 18 '15 at 17:54
  • You can just unpack the jar with unzip or use https://docs.oracle.com/javase/tutorial/deployment/jar/view.html – Norbert Dec 18 '15 at 17:55
  • @fge version 8 at NorbertvanNobelen I don't understand how this would help? I need to read the files when the jar is run, there is no need to view the files. – Eric G Dec 18 '15 at 18:04
  • Well, of course this helps; are you aware that JSR 203 exists? – fge Dec 18 '15 at 18:05
  • Never saw it mentioned when looking at similar topics before posting. Would it be helpful in my situation? – Eric G Dec 18 '15 at 18:07

2 Answers2

0

Try and obtain a FileSystem associated with your source; the matter then becomes pretty simple. Here is an illustration of how to read, as text, all files from a given FileSystem:

private static final BiPredicate<Path, BasicFileAttributes> FILES
    = (path, attrs) -> attrs.isRegularFile();

private static void readAllFilesAsText(final List<Path> paths)
    throws IOException
{
    for (final Path path: paths)
        try (
            final Stream<String> stream = Files.lines(path);
        ) {
            stream.forEach(System.out::println);
        }
}

private static List<Path> getAllFilesFromFileSystems(final FileSystem fs,
    final String pathPrefix)
{
    final Path baseDir = fs.getPath(pathPrefix);

    try (
        final Stream<Path> files = Files.find(baseDir, Integer.MAX_VALUE,
            FILES);
    ) {
        return files.collect(Collectors.toList());
    }
}

Why the mix of "old style" for loops and "new style" lambdas: it is because lambdas just don't handle checked exceptions... Which means you have to do it. For a workaround, see here.

But the gist of it here is to be able to create a FileSystem out of your sources, and you can do it; yes, you can read jars as such. See here.

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

I was able to find a solution using the functions I already had.

I first check to see if the text file can be found normally (Run from an IDE). If a file not found exception occurs, it sets ide = false so it tries to read from the jar.

public void loadWidgets() {

    boolean ide = true;
    String path = "textFiles/widgets/";        
    ArrayList<String> results = new ArrayList<>();
    String dir = new File("").getAbsolutePath() + "/src/Creator/" + path;

    try {
        getWidgetFiles(dir, results);

        results.stream().forEach((s) -> {
            readFile(s);
        });

        updateWidgetVariables();
    } catch (FileNotFoundException e) {
        System.out.println(e.getMessage());
        ide = false;
    }


    if (!ide) {
        CodeSource src = WidgetPanel.class.getProtectionDomain().getCodeSource();
        try {                
            List<String> list = new ArrayList<>();
            if (src != null) {
                URL jar = src.getLocation();
                ZipInputStream zip = new ZipInputStream(jar.openStream());
                ZipEntry ze = null;                    

                while ((ze = zip.getNextEntry()) != null) {

                    String entryName = ze.getName();                        
                    if (entryName.startsWith("Creator/textFiles/widgets") && entryName.endsWith(".txt")) {
                        // Wouldnt work until i added the "/" before the entryName
                        list.add("/"+ entryName);
                        System.out.println("Added name: " + entryName);
                    }
                }
                list.stream().forEach((s) -> {
                    readJarFile(s);
                });

                updateWidgetVariables();

            } else {
                System.out.println("Src null");
            }

        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
    }
}

I then created a new readFile function for reading from a Jar

public void readJarFile(String result) {

    String name = result.substring(result.lastIndexOf("/") + 1);
    String entireWidget = "";
    String line;

    ArrayList<String> vars = new ArrayList<>();
    int begin, end;

    InputStream loc = this.getClass().getResourceAsStream(result);
    try (Scanner scan = new Scanner(loc)) {
        while (scan.hasNextLine()) {
            line = scan.nextLine();
            entireWidget += line;

            while (line.contains("`%")) {

                begin = line.indexOf("`%");
                end = line.indexOf("%`") + 2;
                vars.add(line.substring(begin, end));
                //System.out.println("Variable added: " + line.substring(begin, end));
                line = line.substring(end);
            }

        }
    }
    System.out.println(name + ": " + entireWidget);
    Widget widget = new Widget(name, vars, entireWidget, result);
    widgetList.put(name, widget);

}

Most of this answer is thanks to this question

Community
  • 1
  • 1
Eric G
  • 928
  • 1
  • 9
  • 29