I've been running into issues when trying to accessing files and images in a jar file. The program works as expected before being made into a jar file. I have created a Resources folder used ClassLoader but still getting an error on command line when trying to run the jar file it works but not all the information shows.
The type has to be a File so that the databaseReader can read it.
Error message
java.io.FileNotFoundException: file:\C:\Users\Nicholas\IdeaProjects\MirrorMe\out\artifacts\MirrorMe_jar\MirrorMe.jar!\GeoLite2-City.mmdb (The filename, directory name, or volume label syntax is incorrect)
at java.io.RandomAccessFile.open0(Native Method)
at java.io.RandomAccessFile.open(Unknown Source)
at java.io.RandomAccessFile.<init>(Unknown Source)
at com.maxmind.db.BufferHolder.<init>(BufferHolder.java:19)
at com.maxmind.db.Reader.<init>(Reader.java:116)
at com.maxmind.geoip2.DatabaseReader.<init>(DatabaseReader.java:35)
at com.maxmind.geoip2.DatabaseReader.<init>(DatabaseReader.java:23)
at com.maxmind.geoip2.DatabaseReader$Builder.build(DatabaseReader.java:129)
at sample.LocateMyCity.<init>(LocateMyCity.java:60)
at sample.WeatherToday.getPersonLocationId(WeatherToday.java:102)
at sample.WeatherToday.<init>(WeatherToday.java:126)
at sample.Main.start(Main.java:37)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$162(LauncherImpl.java:863)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$175(PlatformImpl.java:326)
at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
at java.lang.Thread.run(Unknown Source)
Full Code
public class LocateMyCity {
private String myCityLocation;
private String country;
public String getCountry() {
return country;
}
public String getmyCityLocation(){
return myCityLocation;
}
public LocateMyCity() {
try {
ClassLoader classLoader = getClass().getClassLoader();
File database = new File(classLoader.getResource("GeoLite2-City.mmdb").getFile());
URL whatismyip = new URL("http://checkip.amazonaws.com");
BufferedReader in = new BufferedReader(new InputStreamReader(
whatismyip.openStream()));
String ip = in.readLine(); //you get the IP as a String
System.out.println(ip);
// This creates the DatabaseReader object, which should be reused across
// lookups.
DatabaseReader reader = new DatabaseReader.Builder(database).build();
InetAddress ipAddress = InetAddress.getByName(ip);
// Replace "city" with the appropriate method for your database, e.g.,
// "country".
CityResponse response = reader.city(ipAddress);
City city = response.getCity();
System.out.println(city.getName()); // 'Minneapolis'
this.myCityLocation = city.getName();
Country country = response.getCountry();
System.out.println(country.getIsoCode()); // 'GB'
this.country = country.getIsoCode();
System.out.println(country.getName()); // 'United Kindom'
}catch (Exception e){
e.printStackTrace();
System.out.println("Tracing IP E");
}
}
}
Thanks in advance.
When your application is bundled as a jar file, the resources are no longer files but are elements in an archive (the jar file). For a desktop application, the application will typically run without extracting these elements from the archive.
If your database requires an actual file, rather than just a stream it can read from (this would particularly be the case if you needed to write to it), then you cannot use a resource in an archive and will have to use a file on the file system.
You can easily extract the resource from the archive and write its content to the local filesystem. The exact details of how you do this depend on the functionality you need. For example, if you are writing to the database as part of the application's functionality, and expect those changes to persist the next time the application is run, you would only want to extract the resource from the archive on the first run (or possibly if the user deleted the file at a later stage). Normally you would do this by placing the file in the user's home directory. You might do this, for example, with:
Path appDirectory = Paths.get(System.getProperty("user.home"), ".application-name");
Path databaseFile = appDirectory.resolve("GeoList2-City.mmdb");
if (! Files.exists(databaseFile)) {
try {
// create the app directory if it doesn't already exist:
Files.createDirectories(appDirectory);
InputSteam defaultDatabase = getClass().getClassLoader().getResourceAsStream("GeoLite2-City.mmdb");
Files.copy(defaultDatabase, databaseFile);
} catch (IOException exc) {
// handle exception here, e.g. if application can run without db,
// set flag indicating it must run in non-db mode
// otherwise this is probably a fatal exception, show message and exit...
exc.printStackTrace();
}
}
// ...
DatabaseReader reader = new DatabaseReader.Builder(databaseFile.toFile()).build();
If you wanted a new database every time you ran the application, you would probably copy to a temporary file instead, deleting the file when the application exits.
Related
When I try to open an entry in my compiled .jar file, I get the following error (translated from german to english ;)):
java.io.FileNotFoundException: file:/tmp/guest-u9uIBd/Schreibtisch/Untitled.jar!/ressources/db_config.conf (file not found)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at java.io.FileInputStream.<init>(FileInputStream.java:93)
at java.io.FileReader.<init>(FileReader.java:58)
at application.ConnectionProperties.ReadConnectionProperties(ConnectionProperties.java:23)
at application.MainController.ReadConfigFile(MainController.java:218)
at application.MainController.initialize(MainController.java:68)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2548)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2441)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3214)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3175)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3148)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3124)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3104)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:3097)
at application.Main.start(Main.java:15)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$163(LauncherImpl.java:863)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$176(PlatformImpl.java:326)
at com.sun.javafx.application.PlatformImpl.lambda$null$174(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$175(PlatformImpl.java:294)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
at com.sun.glass.ui.gtk.GtkApplication.lambda$null$50(GtkApplication.java:139)
at java.lang.Thread.run(Thread.java:745)
Starting application!
Here is the code:
private void ReadConfigFile() {
try { cp.ReadConnectionProperties(this.getClass().getResource("/ressources/db_config.conf"), dbhost1,
dbport1, dbusername1, dbpasswd1, dbname1);
} catch (IOException e1) {
e1.printStackTrace();
}
}
and
public void ReadConnectionProperties(URL string, TextField dbhost1, TextField dbport1, TextField dbusername1, TextField dbpasswd1,TextField dbname1) throws IOException {
String host, port, uname, password, name;
/** */
FileReader fr = new FileReader(string.getFile());
BufferedReader br = new BufferedReader(fr);
host = br.readLine();
port = br.readLine();
uname = br.readLine();
password = br.readLine();
name = br.readLine();
dbhost1.setText(host);
dbport1.setText(port);
dbusername1.setText(uname);
dbpasswd1.setText(password);
dbname1.setText(name);
br.close();
}
The Folder /ressources/ and the file db_config.conf existed in the .jar file and in the project. He show me only the error, when I want to start the jar. When I start the project in eclipse, he say me no error.
Please help me
The message is correct: you do not have a file named /tmp/guest-u9uIBd/Schreibtisch/Untitled.jar!/ressources/db_config.conf on your computer. The URL you obtained from Class.getResource() refers to an entry inside a jar file. It can not be read using FileReader.
You must use the URL.openStream() method to obtain an input stream from which you can read the contents of that entry. Or use Class.getResourceAsStream() to save a step.
When you ran your project in eclipse, the reason it did not fail is because the classpath entry that contained the file was a directory, and so the URL returned by Class.getResource() just happened to be a file on the local filesystem. When you package your program in a jar file, then the resource you are looking for is inside a jar rather than a local file. Using URL.openStream() will work in both situations.
public void ReadConnectionProperties(URL url, TextField dbhost1, TextField dbport1, TextField dbusername1, TextField dbpasswd1,TextField dbname1) throws IOException {
String host, port, uname, password, name;
/** */
try ( final InputStream stream = url.openStream();
final Reader reader = new InputStreamReader(stream);
final BufferedReader br = new BufferedReader(reader); )
{
host = br.readLine();
port = br.readLine();
uname = br.readLine();
password = br.readLine();
name = br.readLine();
dbhost1.setText(host);
dbport1.setText(port);
dbusername1.setText(uname);
dbpasswd1.setText(password);
dbname1.setText(name);
}
See also try-with-resources.
The clue is in the first line of the exception:
java.io.FileNotFoundException:
file:/tmp/guest-u9uIBd/Schreibtisch/Untitled.jar!/ressources/db_config.conf
(file not found)
That name is NOT a filename. It is a URL. You cannot use FileReader(String) to open a resource. For a start, the resource you are trying to read is not a file. It is actually a component of a file.
So lets have a look at the relevant parts of the code:
cp.ReadConnectionProperties(
this.getClass().getResource("/ressources/db_config.conf"), ...);
public void ReadConnectionProperties(URL string, ...) throws IOException {
FileReader fr = new FileReader(string.getFile());
The getResource call returns a URL which you then pass to your method. I'm going to guess that the actual URL is a "jar:" URL. Specifically:
jar:file:/tmp/guest-u9uIBd/Schreibtisch/Untitled.jar!/ressources/db_config.conf
The method calls URL.getFile() ... but here's what the javadoc say about getFile():
Gets the file name of this URL. The returned file portion will be the same as getPath(), plus the concatenation of the value of getQuery(), if any. If there is no query portion, this method and getPath() will return identical results.
It you understand the URL specification, the "path" of this URL is everything after the first colon; i.e. file:/tmp/guest-u9uIBd/Schreibtisch/Untitled.jar!/ressources/db_config.conf
Then you attempt to use that "file:" URL as if it was a file pathname.
So what is the solution? Well there are lots of them, but a simple one is:
cp.ReadConnectionProperties(
this.getClass().getResourceAsStream("/ressources/db_config.conf"), ...);
public void ReadConnectionProperties(InputStream is, ...) throws IOException {
Reader r = new InputStreamReader(is);
(Note that the reader will read the resource using the platform default character encoding scheme. That might not be the right thing to do.)
I'm making a program where I have to make a file and then deserialize the object in that file. When I name the file something, such as "contacts.dat", I get a FileNotFoundException.
The code is below:
public static void main(String[] args) {
String inputstring = Input.getString("Please enter the name of the file containing the contacts: ");
TreeMap< String, Contact > contactlist = null;
ObjectInputStream in;
try {
in = new ObjectInputStream(new BufferedInputStream(new FileInputStream(inputstring)));
contactlist = (TreeMap< String, Contact >) in.readObject();
in.close();
}
catch(ClassNotFoundException | EOFException emptyexcptn) {
System.out.println("The file provided is currently empty.");
contactlist = new TreeMap< String, Contact >();
}
catch(IOException ioexcptn) {
ioexcptn.printStackTrace(System.out);
System.out.println("Error reading file: " + inputstring);
System.exit(1);
}
Here's what the exception prints:
java.io.FileNotFoundException: contacts.dat (The system cannot find the file specified)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.(FileInputStream.java:138)
at java.io.FileInputStream.(FileInputStream.java:93)
at UnitEight.AssignmentEight.main(AssignmentEight.java:16)
Error reading file: contacts.dat
Your argument to new FileInputStream() is String inputstring = Input.getString("Please enter the name of the file containing the contacts: ");...if Input.getString returns the path for the file then you are pointing to the wrong path anyway.
Print the result of Input.getString()...if any and that would give you a clue what's going on there.
From the API docs -
Constructor Detail
FileInputStream
public FileInputStream(String name) throws FileNotFoundException
Creates a FileInputStream by opening a connection to an actual file, the file named by the path name name in the file system. A new FileDescriptor object is created to represent this file connection.
First, if there is a security manager, its checkRead method is called with the name argument as its argument.
If the named file does not exist, is a directory rather than a regular file, or for some other reason cannot be opened for reading then a FileNotFoundException is thrown.
Parameters:name - the system-dependent file name.Throws:FileNotFoundException - if the file does not exist, is a directory rather than a regular file, or for some other reason cannot be opened for reading.SecurityException - if a security manager exists and itscheckRead method denies read access to the file.
To summarize in to a working example:
When you are using the FileInputStream(String filename), try it by specifying the full (absolute) path to the file so your program can find it. Ex: if your text.dat file was on a shared drive Z: your String you would have to pass as a parameter to the constructor would be
"Z:\\text.dat" instead of using an OS specific slash character it is better to use File.separator in the above example it would look like "Z" + File.separator + "text.dat".
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 7 years ago.
I keep getting a java.lang.NullPointerException when trying to open a txt file in eclipse. Basically, this is a main menu, and when you click the "Rules" button, the rules text file should open. Currently, the txt file is located in a package called "Resources" (which is where all of the other img files I've used in making the game are). Here's the code:
private List<String> readFile(String filename)
{
List<String> records = new ArrayList<String>();
try
{
BufferedReader buff = new BufferedReader(new InputStreamReader(
Configuration.class.getResourceAsStream(filename)));
String line;
while ((line = buff.readLine()) != null)
{
records.add(line);
}
buff.close();
return records;
}
catch (Exception e)
{
System.err.format("Exception occurred trying to read '%s'.", filename);
e.printStackTrace();
return null;
}
}
//action performed
public void actionPerformed(ActionEvent ae) {
JButton b = (JButton)ae.getSource();
if( b.equals(newGameButton) )
{
flag = true;
controller.startGame();
buttonPressed = "newGameBtn";
}
if(b.equals(quitButton))
{
System.exit(0);
}
if(b.equals(ruleButton)){
readFile("../resource/riskRules.txt");
}
}
Appreciate the help!
If "Resources" it's marked as resource in Eclipse. The txt file should be copied to your class path when you build.
As per what I can guess from your code you should be doing something like
Configuration.class.getResourceAsStream("riskRules.txt")
Since your file will be at the root level of your class path.
If for example the file is withing a dir called "text" in your resources you would use something like
Configuration.class.getResourceAsStream("text/riskRules.txt")
There needs to be some level of rudimentary error checking on the result returned from getResourceAsStream before you attempt to use it. Is there a reason you're using getResourceAsStream instead of getResource? If the file exists on disk (I see from your OP that it's because it's in a package, and may not physically exist on the disk), then you can just use that to return the path to it, and create a file object from it.
String path = "/path/to/resource"; // note the leading '/' means "search from root of classpath"
URL fileUrl = getClass().getResource(path);
if (fileUrl != null ) {
File f = new File(fileUrl.toURI());
BufferedReader = new BufferedReader(new FileReader(f));
// do stuff here...
}
else {
// file not found...
}
If you need to pull the file out of the JAR archive, then you can do this:
String path = "/path/to/resource"; // note the leading '/' means "search from root of classpath"
InputStream is = getClass().getResourceAsStream(path);
if (is != null ) {
BufferedReader = new BufferedReader(new InputStreamReader(is));
// do stuff here...
}
else {
// file not found...
}
In the event your resource is not found, you will avoid the NPE and you can properly account for the fact that it's missing.
Note that if you do have your resources in a package (jar), then you cannot use a path to locate it that uses "..", since there is no "relative path" in a jar archive, it's not actually a file on the filesystem.
Your "resources" are located by the relative path you specify in the getResource... method. A leading "/" means to look at the root of your classpath for locating the resource. No leading "/" means to look relative to the location of the class file that you're using to locate the resource.
If your file is in a location called "com.program.resources", and you're trying to locate it from a class called "com.program.someotherpackage.MyClass", then you'd use:
getClass().getResourceAsStream("/com/program/resources/<file.txt>");
to find it.
Here's my example illustrated:
<classpath root>
com
program
resources
file.txt
img.png
someotherpackage
MyClass.class
Generally, it's common practice to leave resources outside your package structure, to avoid confusion when locating them later. Most IDE's have a way to mark your directories as resources, so when the program is compiled, they will be copied to the proper location in the classpath root, and can be found by any class asking for them.
I want to read a file in my java class. My question is similar to this one, but there are two differences. first, I use a different project layout:
/src/com/company/project
/resources
In the resources folder I have a file called "test.txt":
/resources/test.txt
In the project folder I have a class test.java
/src/com/company/project/test.java
I want mu java class to be able to read the contents of test.txt in a STATIC METHOD. I've tried the following:
private static String parseFile()
{
try
{
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
String fileURL = classLoader.getResource("test.txt").getFile();
File file = new File(fileURL);
...
}
}
and the following paths:
File file1 = new File("test.txt");
File file2 = new File("/test.txt");
File file3 = new File("/resources/test.txt");
But they all throw a FileNotFoundException when I want to read the file. How can I correctly declare the path to my file in the snippet above with respect to my project setup and the fact that the method needs to be static?
You should use the class loader of the class which is in the same JAR as the resource instead of the TCCL. And then you need to specify the name of the resource with a full path. And it is typically not good to access those as files. Just open it directly for read (or copy it to a temp file if you need to):
InputStream is =
Project.class.getClassLoader().getResourceAsStream("/resource/test.txt");
BTW: if you simply want to open a file, you need to use a relative file name. This is searched relative to the start dir, which is normally the project main dir (in eclipse):
File resource = new File("resource/test.txt");
(but this wont work if you package it up as a JAR).
After endless trials, I gave up on ClassLoader and getResource methods of any kind.
Absolutely nothing worked, especially if the opening attempt was made from another project. I always ended up getting the bin folder instead of the src folder.
So I devised the following work around:
public class IOAccessory {
public static String getProjectDir() {
try {
Class<?> callingClass = Class.forName(Thread.currentThread().getStackTrace()[2].getClassName());
URL url = callingClass.getProtectionDomain().getCodeSource().getLocation();
URI parentDir = url.toURI().resolve("..");
return parentDir.getPath();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (URISyntaxException e) {
e.printStackTrace();
}
return "";
}
}
The getProjectDir method returns the physical path of the project from which it was called, e.g. C:/workspace/MyProject/.
After that, all you need to do is concatenate the relative path in MyProject of your resource file to open the stream:
public void openResource() throws IOException {
InputStream stream = null;
String projectDir = IOAccessory.getProjectDir();
String filePath = "resources/test.txt";
try {
stream = new FileInputStream(projectDir + filePath);
open(stream);
} catch(Exception e) {
e.printStackTrace();
} finally {
if (stream != null)
stream.close();
}
}
This technique works whether the openResource method is static or non-static, and whether it is called from within the project or from another project on the build path.
It really depends on how your IDE generates output from your project. Typically, classloaders load resources relative to the invoking classes, but if treated right, 'resources' will just end up in the 'root' of your output folder hierarchy, and you can access them accordingly.
For example, if I recreate your code in IntelliJ IDEA, in a class called com/acme/TestClass.class, the following output structure is generated within the IDE when building. This assumes I have "test.txt" sitting in a folder I called "resources", and that folder is specified as being a "resources root":
/com
/acme
TestClass.class
test.txt
The text file ends up in the output folder's root, so accessing it is simple. The following code works for me when I attempt to load the file in a static method within TestClass:
ClassLoader cl = TestClass.class.getClassLoader();
InputStream is = cl.getResourceAsStream("test.txt");
The only thing not covered in the other answers is that your URL conversion to file might not work correctly. If the directories above your project contain a characters that must be decoded then your call to 'getResource("test.txt").getFile()' is not giving you a valid java.io.File path.
I load shader for openGL ES from static function.
Remember you must use lower case for your file and directory name, or else the operation will be failed
public class MyGLRenderer implements GLSurfaceView.Renderer {
...
public static int loadShader() {
// Read file as input stream
InputStream inputStream = MyGLRenderer.class.getResourceAsStream("/res/raw/vertex_shader.txt");
// Convert input stream to string
Scanner s = new Scanner(inputStream).useDelimiter("\\A");
String shaderCode = s.hasNext() ? s.next() : "";
}
...
}
Another method to convert input stream to string.
byte[] bytes;
String shaderCode = "";
try {
bytes = new byte[inputStream.available()];
inputStream.read(bytes);
shaderCode = new String(bytes);
}
catch (IOException e) {
e.printStackTrace();
}
I'm trying to load a .wav file into the memory, but It keep telling me that the file doesn't exists.
String filename;
public MyClass(String _filename){
filename = _filename;
}
public void run(){
InputStream in = View.class.getClassLoader().getResourceAsStream("/sounds/"+filename);
File inputFile = new File(in.toString());
if(!inputFile.exists()){
System.err.println("Wave file not found: " + in.toString());
return;
}
}
Console:
Wave file not found: java.io.FileInputStream#dd5b524
Wave file notfound: java.io.FileInputStream#570add96
The file is in the package folder. It's in
myPackage/sounds/write.wav
EDIT:
Actually I want to load the sound:
InputStream in = this.getClass().getResourceAsStream("sounds/"+filename);
AudioInputStream audioInputStream = null;
try {
audioInputStream = AudioSystem.getAudioInputStream(in);
} catch (UnsupportedAudioFileException e1) {
e1.printStackTrace();
return;
} catch (IOException e1) {
e1.printStackTrace();
return;
}
But the console is still with error:
Exception in thread "Thread-6" Exception in thread "Thread-7"
java.lang.NullPointerException at
com.sun.media.sound.SoftMidiAudioFileReader.getAudioInputStream(Unknown
Source) at
javax.sound.sampled.AudioSystem.getAudioInputStream(Unknown Source)
at com.chrissman.threads.AePlayWave.run(AePlayWave.java:47)
java.lang.NullPointerException at
com.sun.media.sound.SoftMidiAudioFileReader.getAudioInputStream(Unknown
Source) at
javax.sound.sampled.AudioSystem.getAudioInputStream(Unknown Source)
at com.chrissman.threads.AePlayWave.run(AePlayWave.java:47)
in.toString() does not return the path used to open the stream, it returns the class name followed by the hash: java.io.FileInputStream#dd5b524.
The error is because you do not have a file named java.io.FileInputStream#dd5b524 in your current directory.
Since you got an object instead of null as in it found your file. You can not use a File object to get this file, but you have access to it via the in object. Read the contents from the stream and use it.
Resources can be looked up both with a absolute and relative path. What you currently have is an absolute path starting with /. So change it into /myPackage/sounds/write.wav. In general I prefer absolute paths as it can be quite hard to determine which package is the "current" with relative paths.