Passing a .JAR program (ran from terminal) a text file as input - java

I have created a java program that other testers will use to help with their testing. I will be sending them a zip file with the .jar, a readme.txt, and main.properties.txt file.
The main.properties.txt file is a template for the testers to input their DB access credentials. They will update the main.properties file with their db cred's and then attempt to run the .jar from the terminal or command line. The issue I am running into is this. My program needs this updated main.properties.txt file so it can create the connections to our DB's.
What instructions do I need to give in my readme so my program can successfully find the main.properties.txt? Does the main.properties need to be in the same directory as the .jar? Can the testers just create a file on their desktop or documents folders to put the .jar and main.props?
The other question I have is how do I pass this file to my program once its ran from the terminal? Currently it is really easy, because the main.props is part of my program and I can just do something like
Properties prop = new Properties();
FileInputStream in = new FileInputStream("src/main/resources/main.properties");
prop.load(in);
in.close();
But now main.properties is not part of the project anymore. I don't know how to change the code above so that it can find the text from a directory on the local. The location in which they wish to put their main.properties is out of my control so writing a static path will not work. Please help!

There are many ways, I'll show you two.
You need a File object that points to the main.properties file. Then you create a stream on this object new FileInputStream(File) , as you already did by using a String.
The problem of course is to get a relative path to main.properties.txt which works on all systems, regardless where the jar-File is located.
1. Desktop
In this case the main.properties.txt is located at the users desktop. Here is how you access it:
File desktop = new File(System.getProperty("user.home"), "Desktop");
File target = new File(desktop, "main.properties.txt");
Alernativly, if you plan to distribute configuration and property files that do not require user interaction, you may want to use locations like Temp or Documents (Windows).
2. Relative to the jar
Probably one of your best options. Assume the target is in the same folder than the jar-File (or at least in a fix structure relative to the jar). Here is how you access it (related question: how-to-get-the-path-of-a-running-jar-file):
CodeSource codeSource = YourMainClass.class.getProtectionDomain().getCodeSource();
File jarFile = new File(codeSource.getLocation().toURI().getPath());
File jarDir = jarFile.getParentFile();
File target = new File(jarDir, "main.properties.txt");

Related

How do you create a file within a Java artifact?

I am currently working on a Java application in Intellij, and I cannot create a file within my artifact. As an example, I'm using File to create a file within the source, which is MainMenuData.txt.
File mainMenu = new File("MainMenuData.txt");
String absPath = mainMenu.getPath();
mainMenu.createNewFile();
BufferedReader br = new BufferedReader(new FileReader(absPath));
In this, I'm using File to make sure that file exists whenever it isn't.
Instead, I'd like to build within the (Production) artifact. Is that doable?
Anything helps. Thanks.
You could do that.
I assume your artifact is a jar file, which is nothing else than a zip file. You can obtain the location of your jar file in the file system and use the Zip File System to modify it. However I'm not sure, if the jvm might have a problem with that and it might not work on windows, since windows likes to block files, that are in use.
Also this would definitely fail, if your jar file is not stored locally.
A better approach would be to store your data files at the appropriate location in your system.
On Linux(and probably mac): <home>/.local/share/<your application name>/
On Linux(global): /var/lib/<application name>
On Windows(I think, better check it yourself): <appdata>/<your application name>
Your code would look something like this(for Linux):
File home = new File(System.getProperty("HOME");
File configDirectory = new File(home, ".local/share/<application name>");
configDirectory.mkdirs();
File mainMenu = new File(configDirectory, "MainMenuData.txt");
For windows do something similar. If you need both, you should check on which you are currently running.

Windows 10 - ObjectOutputStream can't find relative paths because current working directory is System32

When I call method
System.out.print(new File("").getAbsolutePath())
from main I get the project workspace
C:\Users\darkr\Desktop\NuovoWorkSpace\ProjectName.
When it gets called by our save() method, which serializes what we need, suddenly the absolute path given from
new File("").getAbsolutePath()
becomes System32 (for me) and Desktop directory for my colleagues.
We're using gitHub to share our changes but this makes it almost impossible.
The code you have new File("").getAbsolutePath() is commonly used to determine the current directory from where you launched your application's main(String[]) method. So it looks like you are running from C:\Windows\System32 not on desktop folder.
The easiest way to fix your issue is to edit your application shortcut (see .lnk file and set "Start in" folder), or cd to be in an appropriate writable directory before running your application, or change your application to use file chooser to pick the target location for saves.
Alternatively pick sensible output paths for writing to instead of "", some good candidates are:
// Local user profile
File folder = new File(System.getenv("LOCALAPPDATA"), "myfolder");
// Roaming user profile
File folder = new File(System.getenv("APPDATA"), "myfolder");
// Temp folder:
File folder = new File(System.getProperty("java.io.tmpdir"), "myfolder")
Some sites suggest one of the following lines to locate Desktop, but this is unreliable because it will not work if the folder has been moved or run on some non-English installations:
File maybeDesktop = new File(System.getProperty("user.home"), "Desktop");
Path maybeDesktop = Path.of(System.getProperty("user.home"), "Desktop");
If you want to read the exact location of user Desktop from Java, you need to use JNI/JNA/Panama call to Windows API functions SHGetFolderPath or SHGetKnownFolderPath.

Using .properties file from Java console program

I have created a Java program to compare scripts saved as files in the version management tool to those loaded in our database. It's a simple program, runs through start to finish and outputs to the console when it finds a discrepancy. Now I want to load the database URL, username and password as well as the location of my files from a .properties file.
I did assume that if I put the file on the classpath it would be visible from my Java program:
Properties values = new Properties();
try
{
File checkPackages = new File("myfile.properties");
if(!checkPackages.exists()) throw new FileNotFoundException();
values.load(new FileReader(checkPackages));
}
catch(FileNotFoundException fnfe) {}
I also wanted to save this whole program to a .jar file so that it would be that bit more usable. Unfortunately, the only way I have found to reference the .properties file is to have it in the directory where I am running java.exe. The PATH or the CLASSPATH don't seem to apply??
I found an Oracle site about the .jar file's Manifest file as I was hoping there'd be an answer there, but the Class-path: element in the manifest only seems to refer to .jar files that are not in the .jar (and not .properties files that are!)
Questions:
Is there any way to wrap the .properties file into the .jar file so that my user doesn't have to know it is there?
Is there any way to wrap the Oracle driver .jar into the app's .jar so my user doesn't have to know it is there (Oracle says this needs 'custom code')?
TIA
You can get the resources in your classpath (even when sealed in the JAR) by using the ClassLoader#getResource() and ClassLoader#getResourceAsStream() methods.
For example:
Properties values = new Properties();
values.load(ThisClass.class.getClassLoader().getResourceAsStream("myproject.properties"));
// umm, don't forget to close the stream, this code is just an example usage
Note that storing the username and password to any database in a program is considered a heavy security risk.
One of the appraoch can be to use the -D switch to define a system property on a java command line. That system property may contain a path to your properties file.
E.g
java -cp ... -Dmyproject.properties=/path/to/my.app.properties
my.package.App
Fetch the property in your code as mentioned here:
String propPath = System.getProperty( "myproject.properties" );
final Properties myProps;
final FileInputStream in = new FileInputStream( propPath );
try
{
myProps = Properties.load( in );
}
finally
{
in.close( );
}
Well, I would recommend to encrypt the sensitive data (username, password, url in this case) with public and private keys rather than hiding it. It is afterall not hard to deflate any jar file (which is essentially a zip format) and trace the .properties file

Eclipse-Java: where to put file for Read purpose

I'm programming Java in Eclipse IDE. Here is code I want to read file:
File file = new File("file.txt");
reader = new BufferedReader(new FileReader(file));
I put file.txt in two place:
1) same folder of this SOURCE file.
2) in bin\...\ (same folder of this CLASS file)
But I allways receive NO FILE FOUND.
Please help me.
thanks :)
If the file ships with your application, it would be better accessed as a resource than as a file. Simply copy it to somewhere in your build path and use Class.getResourceAsStream or ClassLoader.getResourceAsStream. That way you'll also be able to access it if you bundle your app as a jar file.
Currently, you're looking for the file relative to the process's current working directory, which could be entirely unrelated to where the class files are.
if you put the file under sources and inside the package "test" for example, the path is:
./src/test/file.txt
you can use
File file = new File("./src/test/file.txt");
System.out.println(file.exists());
The path ./bin/test/file.txt will work in the second case and is more suitable for a normal java project

Trying to update the file in src/web/prod folder (jsp)

I am using jboss, eclipse and svn together. I have to files in my test folder: test/create.jsp and test/data.txt . What I want to do is when I call my create.jsp it will update my data.txt . Obviously I want my data.txt to stay where it is as other scripts are tryong to read from it.
I have tried dozens of new ways to put the path to my File object but for some reason it creates the file under jboss war folders.
Tried:
ServletContext app = getServletContext();
String path1 = app.getRealPath("/");
File f = new File(path1);
// AND
File f = new File("../../data.txt");
Assuming that /test folder is located in the webcontent, then you need the following:
String absolutePath = getServletContext().getRealPath("/test/data.txt");
File file = new File(absolutePath);
or
String webcontentRoot = getServletContext().getRealPath("/");
File file = new File(webcontentRoot, "test/data.txt");
Do you see it? The Java IO only understands local disk file system paths, not URL's or paths outside the context. The ServletContext#getRealPath() is to be used to convert a relative web path to an absolute local disk file system path which in turn can be used further in the usual Java IO stuff. You should never use relative paths in Java IO stuff. You will be dependent on the current working directory which may differ per environment/situation.
That said, you normally don't want to write files to the webcontent. They will get lost whenever you redeploy the WAR. Rather create a fixed disk file system path somewhere else outside the webapp and make use of it. Or even better, make use of an independent SQL database :)

Categories