1

I'm trying to make a runnable jar file and I'm having problems with my .txt files.

My program also have images, but fortunately I've figured out how to manage them. I'm using something like this with them and it works just fine both Eclipse and the jar:

logoLabel.setIcon(new ImageIcon(getClass().getResource("/logo.png")));

My problem is when I've something like this in one of my classes:

try {
    employeeList =  (TreeSet<Employee>) ListManager.readFile("list/employeeList.txt");
} catch (ClassNotFoundException i) {
    i.printStackTrace();
} catch (IOException i) {
    i.printStackTrace();
}

And this in the class ListManager that I use to read my lists serialized in the .txt files:

public static Object readFile(String file) throws IOException, ClassNotFoundException {
    ObjectInputStream is = new ObjectInputStream(new FileInputStream(file));
    Object o = is.readObject();
    is.close();
    return o;
}

I also have a similar method to write in the files.

I've tried several combinations that I've found here:

How to include text files with Executable Jar

Creating Runnable Jar with external files included

Including a text file inside a jar file and reading it

I've also tried with slash, without slash, using openStream, not using openStream... But or I get a NullPointerException or it doesn't compile at all...

Maybe is something silly or maybe is a concept error that I've of how URL class works, I'm new to programming...

Thank you very much in advance for your advice!

EDIT:

It's me again... The answer Raniz gave was just what I needed and it worked perfect, but now my problem is with the method that I use to write in the files...

public static void writeFile(Object o, String file) throws IOException {
    ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(file));
    os.writeObject(o);
    os.close();
}

try {
   ListManager.writeFile(employeeList.getEmployeeList(), "lists/employeeList.txt");
} catch (IOException i) {
   i.printStackTrace();
}

Could you help me please? I don't know what I should use to replace FileOutputStream, because I think there is the problem again, am I right?

Thank you very much!

Community
  • 1
  • 1
Elle518
  • 59
  • 1
  • 10
  • I think I know why you are trying to do this. but its a wrong approach, u should put ur external files (e.g. config, txt, and etc ) in a folder specific to your application. e.g. in userhome/.yourappliactionname – nafas May 01 '15 at 09:40

2 Answers2

2

The problem is that you're trying to access a file inside of a JAR archive as a file in the file system (because that's what FileInputStream is for) and that won't work.

You can convert readFile to use an URL instead and let URL handle opening the stream for you:

public static Object readFile(URL url) throws IOException, ClassNotFoundException {
    ObjectInputStream is = new ObjectInputStream(url.openStream());
    Object o = is.readObject();
    is.close();
    return o;
}

You should also put your code in a try-statement since it currently doesn't close the streams if an IOException occurs:

public static Object readFile(URL url) throws IOException, ClassNotFoundException {
    try(ObjectInputStream is = new ObjectInputStream(url.openStream())) {
        Object o = is.readObject();
        return o;
    }
}

try {
    employeeList =  (TreeSet<Employee>) ListManager.readFile(getClass().getResource("/list/employeeList.txt"));
} catch (ClassNotFoundException i) {
    i.printStackTrace();
} catch (IOException i) {
    i.printStackTrace();
}

I also have a similar method to write in the files.

That won't work if the files are inside the JAR so you should probably consider having your files outside your JAR.

Raniz
  • 10,882
  • 1
  • 32
  • 64
  • Thank you very much! It worked wonderfully, and with the files inside the JAR. But now my problem is with the method that I use to write in the files... I've edited my question to show what I'm doing. – Elle518 May 01 '15 at 20:37
  • The answer to that is that you shouldn't keep files that you need to change in your JAR. If the problem is distribution, create a ZIP of your files and your JAR and distribute that instead. – Raniz May 07 '15 at 00:58
1

Yes, if you want to read resources from inside a jar file, you shouldn't use FileInputStream. Perhaps you should add a readResource method:

public static Object readResource(Class clazz, String resource)
    throws IOException, ClassNotFoundException {
  try (ObjectInputStream is =
           new ObjectInputStream(clazz.getResourceAsStream(resource))) {
     return is.readObject();
  }
}

(I'd also suggest updating your readFile method to use a try-with-resources block - currently if there's an exception you won't close the stream...)

Note that when you say "I also have a similar method to write in the files" - you won't be able to easily write to a resource in the jar file.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194