Reading File from another Package in Java using getResourceAsStream() - java

I am trying to read a file called "numbers.txt" which is filled with int numbers (one int per line, no empty lines). I want to put the numbers into an array and return this array (method readIntsFromFile). Unfoutnetly the File does not get found, so the InputStream cls returns null. If I put the file "numbers.txt" into the same folder as the Class ReadFileInput it works but I do not know why it does not work if I put the "numbers.txt" file into the resources folder. I thought getResourceAsStream() can get it there? The main just creates a new class Object and calls the class function with the parameter "numbers.txt" and saves the result in an array.
Here is the Class with the method readIntsFromFile:
package impl;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
public class ReadFileInput {
public int[] readIntsFromFile(String path) {
ArrayList<Integer> arrList = new ArrayList<>();
try {
InputStream cls = ReadFileInput.class.getResourceAsStream(path);
System.out.println("Get Resources as Stream: " + cls);
//Put cls in ArrayList
}
cls.close();
} catch (Exception e) {
System.out.println(e);
}
int[] arr = arrList.stream().mapToInt(Integer::intValue).toArray();
System.out.println(arr);
return arr;
}
}
Do you know how it could work?
All the best!

The string value you pass to SomeClass.class.getResource() (as well as getResourceAsStream, of course) has two 'modes'.
It looks 'relative to the package of SomeClass', which means, effectively, if you ask for e.g. "img/load.png", and SomeClass is in the package com.foo, you're really asking for "/com/foo/img/load.png" - this is relative mode.
You want to go into absolute mode: You want the 'classpath source' that provided the SomeClass.class file that the JVM used to load the code for SomeClass, and then look in that same place for, say, /img/load.png from there. In other words, if SomeClass's code was obtained by loading the bytecode from jar file entry /com/foo/SomeClass.class in jarfile myapp.jar, you want the data obtained by loading the jar file entry /img/load.png from jarfile myapp.jar. You can do that - simply start with a slash.
Given that your numbers.txt file appears to be in the 'root' of resources, that would strongly suggest the string you pass to .getResourceAsStream() should be "/numbers.txt". Note the leading slash.
NB: It's not quite a path. .. and such do not work. Weirdly, com.foo.numbers.txt would, if the jar file contains /com/foo/numbers.txt.

Related

java.io.FileNotFoundException even when the file path is correct

the code that i used :
package play;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
public class Play {
InputStream music;
public Play() {
URL url=getClass().getResource("/music/Whitewoods - College Kill Dream.mp3");
System.out.println(url.toString());
try {
FileInputStream fileInputStream=new FileInputStream(new File(url.toString()));
fileInputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String args[]) {
new Play();
}
}
the line below int he above code :
System.out.println(url.toString());
prints :
file:/C:/Users/eclipse-workspace/audioboard/bin/music/Whitewoods%20-%20College%20Kill%20Dream.mp3
if i copy this directly and put it in the chrome's url putting box . the file opens but the line :
FileInputStream fileInputStream=new FileInputStream(new File(url.toString()));
gives file not found error.
error stack:
java.io.FileNotFoundException: file:\C:\Users\eclipse-workspace\audioboard\bin\music\Whitewoods%20-%20College%20Kill%20Dream.mp3 (The filename, directory name, or volume label syntax is incorrect)
at java.base/java.io.FileInputStream.open0(Native Method)
at java.base/java.io.FileInputStream.open(FileInputStream.java:213)
at java.base/java.io.FileInputStream.<init>(FileInputStream.java:155)
at play.Play.<init>(Play.java:17)
at play.Play.main(Play.java:26)
thankyou for the help.
You can use the File constructor File(URI uri) transforming your URL url to URI and passing it as an argument for the File constructor like below:
File file = new File(url.toURI());
The file: bit makes what you see not actually a file path, but a URL.
URL has the toFile() method which is closer to what you want, but still isn't what you're actually looking for, which is getResourceAsStream:
The appropriate way to call getResource/getResourceAsStream, is Play.class.getResource, not getClass().getResource. A minor nit; the getClass() variant is non-idiomatic, and strictly worse/less readable: If Play is ever subclassed, it breaks, whereas Play.class.getResource would not. Even if it isn't relevant, better to use the style that is more idiomatic and the right answer is strictly more scenarios.
Generally, if you convert the resource you get into a file you've messed up; the point of getResource is to give you resources from the same place your classes are found, and they need not be files. They could be entries in a jar (which aren't, themselves, files, and cannot be accessed directly either as a java.io.File or as a java.nio.path.Path), pulled in over the network, generated on the fly - anything goes, that's the point of the abstraction. In this case, you're taking your file and immediately turning that into an InputStream. Don't do that - the getResource abstraction can do this.
Like all resources, you can't just open an inputstream like this. You need to ensure it is closed as well, regardless of what happens. Use try-with-resources to ensure this.
Putting it all together:
String songName = "Whitewoods - College Kill Dream.mp3";
try (var in = Play.class.getResourceAsStream("/music/" + songName)) {
// .... do something with 'in' here. It is an InputStream.
}
No need to close it; the try construct will take care of it for you. Doesn't matter how code 'exits' those braces (by running to the end of it, via return or some other control flow, or via an exception) - that inputstream will be closed.

Get path of binary file within a JAR file

I have a jar file when unzipped looks like the following:
models/
com/
com/github/
com/github/
com/github/test/linux-x86_64/
com/github/test/config/
models/model.bin
com/github/test/Test.class
In the Test class, I'm using the path of model.bin inside the getResults method like so:
public class Test {
public List<Label> getResults(String text, int k) {
// Load model from file
loadModel("models/model.bin");
// Do label prediction
return results(text, k);
}
}
The loadModel method above is actually c++ method that looks like this. I am writing a Java Wrapper around a c++ library:
void Testtext::loadModel(const std::string& filename) {
std::ifstream ifs(filename, std::ifstream::binary);
if (!ifs.is_open()) {
throw std::invalid_argument(filename + " cannot be opened for loading!");
}
if (!checkModel(ifs)) {
throw std::invalid_argument(filename + " has wrong file format!");
}
loadModel(ifs);
ifs.close();
}
Currently, when I run this from an IDE, I get an error that says the model.bin file cannot be found. How do I determine the path of the model.bin within a jar file?
It sounds like whatever loadModel is (it is not part of standard java, so you'd have to elaborate) requires an actual file. Which your model.bin resource isn't (it's an entry in a jar).
Check if loadModel has an InputStream based method. It really should; if it doesn't, whatever library this is, does not follow java conventions, and is probably badly written.
If it does:
try (InputStream in = Test.class.getResourceAsStream("/models/model.bin")) {
loadModel(in);
}
will do the trick.
If it doesn't, oh boy. Either fix loadModel yourself, ask its authors to fix it, or if you must work around it, your only option is to copy the resource into an actual file, presumably in a temp dir, and then use that temporary file. This isn't pretty.

Translate package+class name to .class filename

I'm writing a program which analyzes .class files. I want to attach package and class name to my output.
My plan is to write a function which takes the package and class name as input and finds the corresponding .class file (so the user doesn't have to enter that as well, and can't get it wrong), where 'find' should be read as 'give me some data I can use as arguments for BCEL's ClassParser constructor' (either a filename, or a name of a zip file and a name within the zip file).
How do I go about that? Does java come with something which does that? I understand name resolution to be done in the context of a CLASSPATH, so the user should probably supply one of those as well; that's fine.
Note: solutions should not execute any code from the .class file. Just the bytes, ma'm ;-)
Well, if you are using BCEL, everything is already there, see ClassPath:
import java.io.IOException;
import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.util.ClassPath;
public class BcelTest {
public static void main(String[] args) throws IOException {
String classPath=System.getProperty("java.class.path");
// demonstrating with our own class path examplary for an arbitrary path String
ClassPath cp=new ClassPath(classPath);
ClassPath.ClassFile cf=cp.getClassFile(BcelTest.class.getName());
ClassParser p=new ClassParser(cf.getInputStream(), cf.getPath());
JavaClass jc = p.parse();
System.out.println(jc);
// or just using our own system path explicitly
cf=ClassPath.SYSTEM_CLASS_PATH.getClassFile("java.lang.Object");
p=new ClassParser(cf.getInputStream(), cf.getPath());
jc = p.parse();
System.out.println(jc);
}
}
If you already have the classfile, just replace every / in the class name with the directory separator for your system and append .class.
If you want to go from Java class name to bytecode class name, most classes are pretty simple. Prepend the package + '.' and replace '.' with '/'. For inner and nested classes, I'm not sure if there is a simple algorithm.
I want to thank the fine folks in irc://freenode.org/##java for guiding me towards the following recipe:
// replace 'Throwable' with something else in production code :-)
JavaClass recipe() throws Throwable {
URLClassLoader loader = new URLClassLoader(new URL[] {
new URL("file:///usr/share/java/js.jar"),
});
String path = "org/mozilla/classfile/ByteCode.class";
InputStream resource = loader.getResourceAsStream(path);
String fake_filename = "<" + path + ">";
ClassParser classparser = new ClassParser(resource, fake_filename);
JavaClass java_class = classparser.parse();
// System.out.format("%s\n", jc);
return java_class;
}
One could de-hardcode the classpath and the value of path by computing strings in the right format based on user input.
I'm going to use the answer I have accepted because it takes less work on my part, but I want to mention this answer because it is more generally applicable (i.e. with fewer dependencies).

Show file content with scanner class

This is my code:
public static void main(String[] args) {
try {
Scanner in = new Scanner(new File("f.txt"));
System.out.println("Next Double is: ");
System.out.println(in.nextDouble());
} catch (Exception e) {
e.printStackTrace();
}
}
And my "f.txt" is in my class path and I see it in my netbeans left column (that show the class path class files).
But this code throws file not found exception.
Why?
My "f.txt" file:
sdsdsdssf5s1d2s1 d5s s
s dlsfsf1s2 s1fsd1sd
sf31s3ds3ds
dgrh2t4jg6ng52.2 . 32 56. 2df5d5fd
sds2.3 2. 2 . 265.6 . 5 . 3 2 .f3sdsd
I'm not that familiar with netbeans but this looks promising: Netbeans - Reading a data file in src folder
In essence, put the entire path rather than the filename or move it to the build folder.
You could also consider using the class loader to read files as resources inside packages using getClass().getResourceAsStream("f.txt");. This is the preferred way of accessing resources since you no longer have to worry about absolute vs. relative paths. If a resource is in your classpath, you can access it.
it's recommend to use the ClassLoader as returned by Thread.currentThread().getContextClassLoader(), if the application uses multiple class loaders
This is a veeeeeeeeeeeery common problem in Java begginners.
First of all understand this theory:
If you have a package com.example, by common sense you would put the file in there NOO!
You must put the file in the root of all, (folder previous to com folder).
So you have to put f.txt in MyProject folder and everything will be okay.
About the mismatch exception, try to don't use such insecure methods as nextDouble(). What happens is that the reader is trying to cast the first 4 bytes as a double ("sd" string), and obviously that will throw an exception. Try to read line by line or character by character and do a simple char array from an array list.

.java file path to class name

What's the most efficient way of getting the class(es) created on a .java file? I have the .java file path and I need to get the class full name.
I can only remember:
Compile it with JavaCompiler
Using the file text to parse it with Eclipse ASTParser (or another)
Infer the class name through part of the file path, but I don't know
if this works for every cases
Somehow, use a tool like javap (dind't really thought about this one)
EDIT
I have this file, located at C:\myfolder\MyClass.java (let's ignore package and folder association conventions):
package mypackage.mysubpackage;
public class MyClass
{
// my class implementation here
public class MyInnerClass
{
// my inner class implementation here
}
}
The full name of the classes declared in this file are:
mypackage.mysubpackage.MyClass
mypackage.mysubpackage.MyClass.MyInnerClass (I don't know if this
one it's correct, but let's pretend it is)
How can I get those class when I only have the .java file path (C:\myfolder\MyClass.java) ?
The only way to reliably obtain the names of the classes (mind that it may also define interfaces) files a .java file declares would be to really parse the java language contained in that file.
And even then you will need to know which compiler will be/has been used to compile the .java file, as a java compiler could use any naming convention it likes for anonymous classes (the Oracle compiler uses $1, $2..., but there is no strict need to mimic that behavior).
Considering these obstacles I believe its very hard to do from the .java files contents and simply impossible with the .java files path alone.
The most effective way is Class.forName().getName()
I have the .java file path and I need to get the class full name.
Which means, you know the path of .java file and you want the class name of each class file.
class Filter {
public static void main(String[] a) {
Filter f = new Filter();
String dirName = "D:\\Yourfolder\\"; // assuming your java file are located in D:\Yourfolder\
f.finder(dirName); // call the method for listing all the class file
}
public File[] finder(String dirName) {
File dir = new File(dirName);
return dir.listFiles(new FilenameFilter() {
public boolean accept(File dir, String filename) {
if(filename.endsWith(".class"))
{
System.out.println(filename);
}
return filename.endsWith(".class");
}
});
}
}
Replace dirName with your .java directory path.
One approach is to scan the directory tree where your Java source files are located, and for each file ending in ".java", you take its full folder path as a String and convert each dir separator to a '.' character. This will give you the fully qualified class name (FQCN). For example, if the path is: com\foo\fee\Foo.java, that becomes com.foo.fee.Foo.
Of course, this does not give you inner or nested classes and other advanced things, but these are created when you compile.
I have seen this kind of directory scanning in many frameworks, even Spring.
I am working on this in Groovy, so far I have:
File file = new File(rootSourcePath)
file.eachFileRecurse(FILES){
def path =it.getAbsolutePath()
println path
if(path.endsWith(".java")){
// to do the conversion here
}
}
Hope this interpreted your question correctly.
To get the name of the class file Try this
void printClassName(String classname)
{
System.out.println("The class name " + classname +" is " + classname.getClass().getName());
}

Categories