Win a copy of Transfer Learning for Natural Language Processing (MEAP) this week in the Artificial Intelligence and Machine Learning forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Tim Cooke
  • Paul Clapham
  • Devaka Cooray
  • Bear Bibeault
Sheriffs:
  • Junilu Lacar
  • Knute Snortum
  • Liutauras Vilda
Saloon Keepers:
  • Ron McLeod
  • Stephan van Hulst
  • Tim Moores
  • Tim Holloway
  • Piet Souris
Bartenders:
  • salvin francis
  • Carey Brown
  • Frits Walraven

Read/write to text file in IDE or getResource in JAR (using same source code)

 
Greenhorn
Posts: 26
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hello Code Ranchers,

My Swing GUI program saves a few user settings in a text file located in the project folder. Until a couple days ago, I've been running and testing exclusively in Eclipse IDE. So, I've just become aware that I can't read a file once I've packaged my project into a runnable jar in the same way I can while I'm in the IDE.

Using the IDE, my code to access and read a text in a file is something like this:


In addition, if a user enters a string into a text box and "executes" a method, those updated strings are overwritten in the text file. That code looks something like this:


From what I understand, I need to use getResource to access those same text files once I've packaged as a jar. Is there any tidy way to alter my source to run using my current code while running in the IDE, but then to use getResource when I'm running the jar? Any feedback here is appreciated.

Thanks,
 
Bartender
Posts: 7077
65
Eclipse IDE Firefox Browser MySQL Database VI Editor Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
With  both Eclipse and the jar you should be using getResources(). One problem that you'll run into is that you can't modify a resource file in your program. The best way to deal with this is to first look for the file in its relative project path, if you find it, use it. If you don't find it then open up the file in the resources and copy it to the relative path and then from there open the relative path and continue using it. Any update should be written to the relative path.
 
Simon McNamara
Greenhorn
Posts: 26
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hello Carey,

Many thanks for your reply. I've done a bit of homework on your response before returning.

It seems that all getResource() solutions involve reading the text as a stream. I think I can deal with that okay, but I've been unable to get a working code snippet to build from. I thought I'd start by printing the stream to console. Below, I'm just trying to confirm that my code can actually find the resource.

I've tried several variations of this as a jar and in Eclipse:


In every case, I get

Can't find the resource

to console. Obviously I'm not finding the text file correctly. I suspect my path is just wrong. I've tried a number of paths:



Attached is a screen show of my file structure. Should I be able to use this same code in the IDE and jar?

I'm confused about the use of the getResourceAsStream() method. Should "Swing" be the name of the class from where this call is being made?

Many thanks for your help.

Screen-Shot-2020-04-26-at-12.08.32-PM.png
[Thumbnail for Screen-Shot-2020-04-26-at-12.08.32-PM.png]
 
Sheriff
Posts: 21922
106
Eclipse IDE Spring VI Editor Chrome Java Ubuntu Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Resources are files that are on the class path. With a normal Maven layout, that means they should go somewhere in src/main/resources (or src/test/resources for resources that are needed only for unit tests). I notice you have a different layout, but I do see a resource folder. Put the file in there, then you should be able to read it as a resource.
 
Carey Brown
Bartender
Posts: 7077
65
Eclipse IDE Firefox Browser MySQL Database VI Editor Java Windows
 
Simon McNamara
Greenhorn
Posts: 26
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hello Rob and Carey,

Thanks for your replies. I got it working using the path as follows:



Then I used Scanner to get the nextLine() method, similar to my original BufferedReader implementation:



As Cary mentioned, the problem indeed is how to change the content of the file. I found this on StackOverflow, describing my problem: https://stackoverflow.com/questions/2797367/write-to-a-file-stream-returned-from-getresourceasstream

The second responder suggests this:



But cautions that this might be problematic for Windows users. I'm also not clear what a URL object actually is. (I'm on MacOS and plan to deploy to Raspian, but stability in Windows would be very valuable.) Can either of you give any feedback as to why this would be unstable in Windows? Any additional pointers or ideas for how to indirectly edit the resource file is appreciated.

Thanks,
 
Marshal
Posts: 25452
65
Eclipse IDE Firefox Browser MySQL Database
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Simon McNamara wrote:As Cary mentioned, the problem indeed is how to change the content of the file. I found this on StackOverflow, describing my problem: https://stackoverflow.com/questions/2797367/write-to-a-file-stream-returned-from-getresourceasstream



In your original post you mentioned that you packaged up the project in a JAR file. That means that the resource is inside the JAR file, which means that you can't change it.

But as the third responder to that SO thread said, you shouldn't be changing a project resource anyway. Even if it's, say, default settings which can be changed by the user. What you should do instead is to put a copy of the resource in the user's home directory and work with that. The process is like this:

1. Look for a file in the user's home directory.

2. If it's not there, copy from the resource in the JAR to that file.

3. Open that file and modify away.

The system property "user.home" gives you the location of the user's home directory.
 
Simon McNamara
Greenhorn
Posts: 26
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hello all,

Many thanks for your replies. In the end, I realized that for my application, I really didn't need a resource file at all. On startup, if A_record_file.txt doesn't exist, I create the directory. If it does exist, I grab the appropriate Strings and assign them to the GUI.

For future users, I get the home directory with:



Thanks for your help.
 
Saloon Keeper
Posts: 21975
150
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Actually, changeable resources are generally known as "preferences". Support for Preferences has been around for a long time - since Java 1.4. It provides an abstract mechanism for preference handing.

https://docs.oracle.com/javase/8/docs/api/java/util/prefs/Preferences.html

The way it generally works is that you put your default preferences in a resource - sometimes several resources - in your JAR. Then when the user runs the application, they may create (unknowingly) user-specific preference data as part of application startup, and likewise, some of their operating environment - say, window sizes and positions - might get written to preferences on shutdown. In between, there will often be a Preferences menu on the File or Edit menus (or occasionally somewhere less obvious) where they can set personal preferences. It all goes into the Preferences subsystem.

Traditionally in Unix, and thus Linux, the user preferences would go into an invisible ("dot") file for the application - or sometimes an invisible directory. However, that was getting to the point that half of one's home directory was preferences, so a preferred option these days is to make app-specific subdirectories under $HOME/.config.

Also, it is not uncommon to have global preferences. In Unix, those are usually under application-specific subdirectories under the /etc directory. So you have a hierarchy: internal (resource file(s)), global, and user, with each layer taking precedence over the previous one and generally only including those values that override lower-level items.

Preference file formats can be whatever you want. Commonly, people use Java properties files, Windows .INI files, XML files, or the like, but the actual preferences interface is flexible. You should, for example, be able to keep preferences in a SQLite database or even on an independent server.
 
Simon McNamara
Greenhorn
Posts: 26
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hey Tim,

Thanks for posting about Preferences. I'll check that out. Seems like my solution detailed in my previous post is pretty similar to global preferences.

Many thanks,
 
Ever since I found this suit I've felt strange new needs. And a tiny ad:
Two software engineers solve most of the world's problems in one K&R sized book
https://coderanch.com/wiki/718759/books/Building-World-Backyard-Paul-Wheaton
    Bookmark Topic Watch Topic
  • New Topic