Is there a way to read programmatically a .jmod file in Java? - java

I opened a .jmod file with 7-zip and I can see the contents. I tried to read it with ZipInputStream programmatically but it doesn't work: does someone know how to do it?

There is no documentation in JEP 261: Module System regarding the format used by JMOD files. That's not an oversight, as far as I can tell, because leaving the format as an implementation detail means they can change the format, without notice, whenever they want. That being said, currently JMOD files appear to be packaged in the ZIP format; this other answer quotes the following from JEP 261:
The final format of JMOD files is an open issue, but for now it is based on ZIP files.
However, I can't find that quote anywhere in JEP 261. It looks to be from an older version of the specification—at least, I found similar wording in the history of JDK-8061972 (the issue associated with the JEP).
What this means is you should—for the time being—be able to read a JMOD file by using any of the APIs which allow reading ZIP files. For instance, you could use one of the following:
The java.util.zip API:
import java.io.File;
import java.io.IOException;
import java.util.zip.ZipFile;
public class Main {
public static void main(String[] args) throws IOException {
var jmodFile = new File(args[0]).getAbsoluteFile();
System.out.println("Listing entries in JMOD file: " + jmodFile);
try (var zipFile = new ZipFile(jmodFile)) {
for (var entries = zipFile.entries(); entries.hasMoreElements(); ) {
System.out.println(entries.nextElement());
}
}
}
}
Note: To read the contents of an entry, see ZipFile#getInputStream(ZipEntry).
The ZIP FileSystemProvider API:
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
public class Main {
public static void main(String[] args) throws IOException {
var jmodFile = Path.of(args[0]).toAbsolutePath().normalize();
System.out.println("Listing entries in JMOD file: " + jmodFile);
try (var fileSystem = FileSystems.newFileSystem(jmodFile)) {
Files.walk(fileSystem.getRootDirectories().iterator().next())
.forEachOrdered(System.out::println);
}
}
}
Note: To read the contents of an entry, use one of the many methods provided by the java.nio.file.Files class.
Note: The Path#of(String,String...) method was added in Java 11 and the FileSystems#newFileSystem(Path) method was added in Java 13. Replace those method calls if using an older version of Java.
To reiterate, however: The format used by JMOD files is not documented and may change without notice.

Related

Get normalized path for windows location in Java

I have a requirement where I have a path as C:\..\bar
for this the file bar gets created in the C drive when I use this path in SQL server.
Now on using Apache's FilenameUtils, The normalize method returns null as also documented.
C:\..\bar --> null
But I want
C:\bar for C:\..\bar
Is there any way in Java to get C:\bar for C:\..\bar
I know that .. would mean parent directory but SQL server still creates file the C drive.
The issue with using File or Path classes is that they make use of underlying Filesystem, which in my case is Unix but the path I will get will be windows absolute path.
So basically want to get rid of any redundancy like dots and slashes irrespective of the file system.
You can use getCanonicalFile.
import java.io.File;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
File file = new File("C:\\..\\bar");
System.out.println(file.getCanonicalPath());
}
}

How to create an ArrayList of Text Files in Java?

I'm trying to create an ArrayList of pre-existing text files (basically take a folder of text files that are already saved on my computer and plug them into an ArrayList) so that I can iterate over them and send matching pairs of text files to another program (a separate java program) for data analysis. Is it possible to create an ArrayList of text files the way I want to?
Ever since the java.nio package was introduced, this has become simple enough, especially with Java 8 streams:
Files.walk(new File("/your/base/dir").toPath()) // stream of all files inside base folder
.filter(p->p.getFileName().endsWith(".txt")) // limit to .txt files
.map(Path::toAbsolutePath) // convert to absolute pathy
.forEach(System.out::println); // print
See: Files.walk(path, option...)
In apache commons-io, there is a class called FileUtils which will return a List of Files.
package test;
import java.io.File;
import java.io.IOException;
import java.util.List;
import org.apache.commons.io.FileUtils;
public class TestFiles {
public static void main(String[] args) throws IOException {
File dir = new File("<dir>");
String[] extensions = new String[] { "txt" };
List<File> files = (List<File>) FileUtils.listFiles(dir, extensions, true);
}
}

Java-Copy file.txt inside org which is a folder in A.jar without extracting z.jar file

I was trying to copy a file into a A.jar (without extracting it) but it didn't work. Suppose I have file "copy.txt" in "D:\java\copy.txt" and i want this file to be copied into my "A.jar/org/here" . if the file is already exist then it should replace it.
i tried modifying the below code but it didn't work.
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class deploy {
public static void main(String[] argv) {
Path myFilePath = Paths.get("C:/Users/ma329300/Desktop/copy.txt");
Path zipFilePath = Paths.get("D:/java/A.jar");
try( FileSystem fs = FileSystems.newFileSystem(zipFilePath, null) ){
Path fileInsideZipPath = fs.getPath("/org/copy.txt");
Files.copy(myFilePath, fileInsideZipPath);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
First of all, check your paths. Java is really tricky with the paths and should be in full path form.
Try putting the backslashes like "D:\java\A.jar", as windows works differently than linux.
Also, if you change your file and re-compile, it will generate a new .jar each time, with the updated file you wanted to change. That would solve your problem without having to access your .jar externally.
I tried once to access libraries packed on a .jar and load them with the code inside the .jar too and didn't worked propperly, so be carefull.
Another thing you should be aware of is that you cannot modify a .jar directly without decompressing, as it uses a special algorythm in order to get the indexation properly done for and by java. Changing one specific part of the .jar could corrupt the data into it and make it crash on the run.
Hope it helped.

Why can my library not access its resources?

I have a class that reads a file:
package classlibrary;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
public class ReadingResource {
public static String readResource() throws IOException {
URL resource = ClassLoader.getSystemClassLoader().getResource("classlibrary/test_file.txt");
BufferedReader br = new BufferedReader(new FileReader(resource.getPath()));
return br.readLine();
}
}
The resource file is in the same directory where this class is.
I made a library out of this class and the file.
Now I want to use it in the other class:
package uritesting;
import classlibrary.ReadingResource;
import java.io.IOException;
public class URITesting {
public static void main(String[] args) throws IOException {
System.out.println(ReadingResource.readResource());
}
}
When I make a .jar file out of this class, set the class as the main class, add the .jar from above and execute it as "java -jar URITesting.jar" I get a FileNotFoundException, saying the class ReadingResource can not find the specified file. It is funny because the path that is specified in the exception message is actually the correct path to the file.
You can find the files here.
EDIT:
I developed the project in NetBeans. When I run it there, it works fine. The classpath is different in that case. It contains both resources of the URITestingProject and ReadingResource.
However, when I run it as a standalone JAR, the classpath contains URITestingProject only. What is strange to me is that it doesn't complain about not finding the class ReadingResource. It means that it is loaded, although it is not in the classpath :/
The problem is resource.getPath(). It's not possible to calculate a path ,valid for a file reader, inside a jar file, on another server and so on. However you can get the data through a stream instead:
InputStream data = ClassLoader.getSystemClassLoader().getResourceAsStream("classlibrary/test_file.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(data, "utf-8"));
As a side note: When reading with reader it's a good idea to specify the encoding:

Java - FilenotfoundException for reading text file

by running this...
File file = new File("Highscores.scr");
i keep getting this error, and i really don't know how to get around it.
the file is currently sitting in my source packages with my .java files.
I can quite easily read the file by specifying the path but i intend to run this on multiple computers so i need the file to be portable with the program.
this question isnt about reading the text file but rather specifying its location without using an absolute path .
ive searched for the answer but the answers i get are just "specify the name" and "specify the absolute path".
id post an image to make it more clear but i dont have the 10 rep to do so :/
how do i do this?
cheers.
The best way to do this is to put it in your classpath then getResource()
package com.sandbox;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
public class Sandbox {
public static void main(String[] args) throws URISyntaxException, IOException {
new Sandbox().run();
}
private void run() throws URISyntaxException, IOException {
URL resource = Sandbox.class.getResource("/my.txt");
File file = new File(resource.toURI());
String s = FileUtils.readFileToString(file);
System.out.println(s);
}
}
I'm doing this because I'm assuming you need a File. But if you have an api which takes an InputStream instead, it's probably better to use getResourceAsStream instead.
Notice the path, /my.txt. That means, "get a file named my.txt that is in the root directory of the classpath". I'm sure you can read more about getResource and getResourceAsStream to learn more about how to do this. But the key thing here is that the classpath for the file will be the same for any computer you give the executable to (as long as you don't move the file around in your classpath).
BTW, if you get a null pointer exception on the line that does new File, that means that you haven't specified the correct classpath for the file.
As far as I remember the default directory with be the same as your project folder level. Put the file one level higher.
-Project/
----src/
----test/
-Highscores.scr
If you are building your code on your eclipse then you need to put your Highscores.scr to your project folder. Try that and check.
You can try to run the following sample program to check which is the current directory your program is picking up.
File f = new File(".");
System.out.println("Current Directory is: " + f.getAbsolutePath());

Categories