I just did a little project in java, packed the .jar and application.properties to my VPS and wanted to test it there. The tool reads logfiles.
I specified the path to the logfile within the application.properties as follows:
LOGPATH=/folder1/folder2/logs/thelogIwant.log
The path is parsed as follows:
public String makePath(String path) {
Properties prop = new Properties();
InputStream input = null;
try {
input = new FileInputStream("application.properties");
prop.load(input);
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return prop.getProperty(path);
}
Path logFile = Paths.get(makePath("LOGPATH"));
It even seems to to this right, as the ErrorMessage states:
SEVERE: /folder1/folder2/logs/thelogIwant.log (No such file or directory)
The logfile is being created by another application and therefore in another directory than the .jar I am running.
The path exists on my VPS and I can navigate to and through it.
Can someone point me in the right direction? What's going wrong here?
Things I tried:
Specify path with "~/folder1/..."
Specify path with "folder1/..."
I can think of a few possible explanations:
The pathname in your config file is wrong; e.g. there is a typo or some other discrepancy that you didn't notice.
You are loading a different property file to the one that you think.
There is a mismatch between the property name in the file and the name that your tool uses.
The other application didn't create the log file
Permissions: your tool may be running as a user that isn't permitted to read one of the directories on the path.
SELinux in enforcing mode can prevent an application (e.g. running as a service) from accessing files.
Homoglyphs, either in the property file1, your source code or the name of the file in the file system.
The things that you tried are unlikely to work. A correct absolute pathname is more robust than a relative pathname, and Paths.get doesn't know how to deal with ~. (The expansion of ~ is a shell feature ....)
I would try this:
Modify your tool to output the value of the "LOGPATH" property ... enclosed in quote characters so that you can see any spurious whitespace characters at the beginning / end of the value.
Run the tool.
Using copy-and-paste, see if you can open the file using exactly the pathname that your tool uses.
In short, verify that the pathname you are actually using is what you expect it to be.
1 - In practice, classic format property files are encoded in LATIN-1, so this is impossible.
I was able to fix this, thanks #Steven for your help!
I used the pwd command when in the directory the files are in and recognized that the true absolute path starts with /home/myusername/folder1/...
Works fine now.
Related
tl;dr I'm more used to writing command-line scripts that can just output based on the current working directory, so I'm unsure what directory to use for output files in a program that will be launched from a JAR.
Program Description:
My program builds an HTML file from data given to it from the rest of the program, and then is supposed to write it to a file that we'll call "Output.html" for simplicity.
Relevant Code:
public void outputHTML()
{
String output = buildHTML();
// Expanded to explain my confusion better
String fileDirectory = ""; // ???
String fileName = "Output.html";
String fullPath = fileDirectory + "\\" + fileName;
try (BufferedWriter writer = new BufferedWriter(new FileWriter(fullPath)))
{
writer.write(output);
writer.close();
} catch (IOException e)
{
System.out.println("File not found.");
e.printStackTrace();
}
}
Problem
I don't know what to put the file directory as. Usually I run my programs from the command line and use ".\\Output.txt" as my output path, but I don't know where to put it if it's being run from a JAR.
The desired file structure is as follows:
Encompassing Folder
Program.jar
output
Output.html
Or alternatively (not sure if this makes it easier to understand or harder):
main\
main\Program.jar
main\output\
main\output\Output.html
Everything I can find on SE only relates to reading files that are both immutable and internal, but I'm trying to output a non-static file to a location outside of my jar.
Can anyone help with this? Thanks!
Misc Details
I'm using Eclipse without Gradle currently, because I don't know what Gradle is and new things are scary. If this particular problem would be easier to solve with Gradle, let me know and I'll look up more about it.
EDIT:
Added syntax highlighting to code block.
Formatted everything a bit better
Changed title to be more descriptive
You can use an absolute path: e.g. fileDirectory = "\\project\\test\\main\\output";
using normal slash should also work even on Windows ("/project/test/main/output")
Or use a relative path - this will start from the current working directory (user directory), the one where the JVM was started in - e.g. fileDirectory = "main\\output";
I'm trying to use a file in my code but I don't want to have specify the absolute file path, only the file name, for example "fileName.txt".
I want to do this so I have the ability to use this code on different laptops where the file may be stored in different folders.
The code below is what I'm using at the moment but I receive a NoSuchFileException when I ran it.
FileSystem fs FileSystems.getDefault();
Path fileIn = Paths.get("fileName.txt");
Any ideas how to overcome this problem so I can find the file without knowing its absolute path?
Ideas on how to find the file without knowing its absolute path:
Instruct the user of the app to place the file in the working directory.
Instruct the user of the app to give the path to the file as a program argument, then change the program to use the argument.
Have the program read a configuration file, found using options 1 or 2, then instruct the user of the app to give the path to the file in the configuration file.
Prompt the user for the file name.
(Not recommended) Scan the entire file system for the file, making sure there is only one file with the given name. Optional: If more than one file is found, prompt the user for which file to use.
if you don't ask the user for the complete path, and you don't have a specific folder that it must be in, then your only choice is to search for it.
Start with a rootmost path. Learn to use the File class. Then search all the children. This implementation only returned the first file found with that name.
public File findFile(File folder, String fileName) {
File fullPath = new File(folder,fileName);
if (fullPath.exists()) {
return fullPath;
}
for (File child : folder.listFiles()) {
if (child.isDirectory()) {
File possible = findFile(child,fileName);
if (possible!=null) {
return possible;
}
}
}
return null;
}
Then start this by calling either the root of the file system, or the configured rootmost path that you want to search
File userFile = findFile( new File("/"), fileName );
the best option, however, is to make the user input the entire path. There are nice file system browsing tools for most environments that will do this for the user.
private void copyFile() throws IOException {
Path destination;
String currentWorkingDir = System.getProperty("user.dir");
File fileToCopy = component.getArchiveServerFile();
if (path.contains(File.separator)) {
destination = Paths.get(path);
} else {
destination = Paths.get(currentWorkingDir + File.separator + path);
}
if (!Files.exists(destination)) {
try {
Files.createDirectories(destination);
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
FileUtils.copyFileToDirectory(fileToCopy, new File(destination.toString()));
}
}
Basically what I'm trying to do here is copying a file in some location using the path provided in the class's constructor. The logic is like this:
If the path has file separator, I consider it a full path and copy the file at the end.
If the path doesn't have file separator, I copy the file in the working directory from which the .exe file was launched.
So far, only the first option works (the full path). For some reason, the working directory option is not working and I can't figure out why.
UPDATE: If I just change the following line:
String currentWorkingDir = System.getProperty("user.dir");
to
String currentWorkingDir = System.getProperty("user.home");
It works. So I'm guessing the problem is coming from user.dir? Maybe at runtime, the folder is already being used and as a result, it can't copy the file into it?
The weird thing is, I don't have any exceptions or error, but nothing happens as well.
UPDATE 2: I think the problem here is that I'm trying to copy a file which is embedded in the application (.exe file) that I'm executing during runtime, and java can't copy it while the current working directory is being used by the application.
UPDATE 3:
Since this copy method is used in an external library, I had to come up with another way (other than logs) to see the content of system property user.dir. So I wrote I little program to create a file and write in it the value return by the property.
To my surprise, the path is not where my application was launched. It was in:
C:\Users\jj\AppData\Local\Temp\2\e4j1263.tmp_dir1602852411
Which is weird because I launched the program from :
C:\Users\jj\workspace\installer\product\target\
Any idea why I'm getting this unexpected value for user.dir?
I have a file named error.log.1.
I would like to tell Java to use the system editor to open this file.
If it were named error.log, then the following would work:
Desktop.getDesktop().edit(new File("error.log") );
However, since it is not a recognized file extension, it doesn't open. Instead I get an error:
Exception in thread "main" java.io.IOException: Failed to open error.log.1.
Error message: No application is associated with the specified file for this operation.
at sun.awt.windows.WDesktopPeer.ShellExecute(Unknown Source)
at sun.awt.windows.WDesktopPeer.open(Unknown Source)
at java.awt.Desktop.open(Unknown Source)
at net.joshuad.hypnos.workbench.EditorTest.main(EditorTest.java:9)
I am not sure what "System Editor" is, but if it is a specific application you want to open, you'll need to run that application and pass the log filename as an argument.
You will need to determine the path to the application and then you can use the Runtime.getRuntime().exec() method to open the file.
For example, if you wanted to open the log file using Notepad, you could do so like this:
Runtime.getRuntime().exec("C:\\Windows\\System32\\notepad.exe error.log.1");
This, of course, assumes the application accepts a filename as a parameter. You'll need to look into what commandline syntax this System Editor has.
There are two ways to handle this problem:
renaming your file and then open it as you mentioned;
explicitly using an command (the editor) to open the file;
In the second case, it will be something as:
private static void openByCommand(String filePath){
try {
Process process = new ProcessBuilder("gedit", filePath)
.directory(new File("/home/hearen")) // set up your working directory;
.start();
int exitCode = process.waitFor();
System.out.println(exitCode);
} catch (IOException | InterruptedException ignored) {
ignored.printStackTrace();
}
}
As suggested by Zephyr, a good solution would be to specify the path to the default editor (Write some code to be platform specific). Or better yet, you could package your own cross-platform text editor, something like jEdit could be a good option.
However, if you really want to use Desktop.getDesktop().edit(path), then a hack is to simply check the file extension, and if it is unknown then add to ".log" or ".txt" to the end.
A bit like this:
File originalName = new File("path/to/my/file/error.log.1");
File appendedName = new File(originalName.getAbsolutePath()+".log");
boolean success = originalName.renameTo(appendedName);
if (success) {
Desktop.getDesktop().edit(appendedName);
}
//Change it back when you are done:
appendedName.renameTo(originalName);
Obviously this will not work if multiple sources/applications are reading from the original file at the same time (You could make a copy instead of renaming it), but it may fit your use case.
I'm developing a program with NetBeans 8.0 and JavaFX Scene Builder 2.0 that need store some variables in a file, where admin users can modify it when needed, (like change server IP address, or a number value from a no editable textfield) and if they close and load again the program, the changes made in variables are kept. Like any settings section of a program.
I just try do it with the Properties file, but i have problems to store it in the same folder as .jar file. When the program execute the line new FileOutputStream("configuration.properties"); the file is created at root of the disk. As the folder of the file can be stored anywhere, i not know how indicate the right path.
Creating the properties file in the package of the main project and using getClass().getResourceAsStream("configuration.properties"); i can read it but then i can not write in for change values of variables.
Is there a better method to create a configuration file? Or properties file is the best option for this case?
My other question is whether it is possible to prevent access to the contents of the file or encrypt the content?
PD: I've been testing this part of the code in Linux operating system currently, but the program will be used in Windows 7 when ready.
If you use Maven, you can store your property files in your resources folder, say resources/properties/. When you need to load them, do this:
private Properties createProps(String name)
{
Properties prop = new Properties();
InputStream in = null;
try
{
in = getClass().getResourceAsStream(name);
prop.load(in);
}
catch (IOException ex)
{
System.err.println("failed to load \"" + name + "\": " + ex);
}
finally
{
try
{
if (in != null)
{
in.close();
}
}
catch (IOException ex)
{
System.err.println("failed to close InputStream for \"" + name + "\":\n" + FXUtils.extractStackTrace(ex));
}
}
return prop;
}
Where name is the full path to your properties file within your resources folder. For example, if you store props.properties in resources/properties/, then you would pass in properties/props.properties.
I am not 100% sure if you can carry over this exact procedure to a non-Maven project. You'd need to instruct whatever compiler tool you are using to also include your property files.
As far as your final question goes, in regards to encrypting your properties, I would consider posting that as a separate question (after having done thorough research to try to discover an existing solution that works for you).
At last i found how obtain the absolute path from folder where is .jar file to create properties file in, and read/write it. Here is the code:
File file = new File(System.getProperty("java.class.path"));
File filePath = file.getAbsoluteFile().getParentFile();
String strPath = filePath.toString();
File testFile = new File(strPath+"/configuration.properties");
Tested in Ubuntu 13.04 And Windows 7 and it works.
For encrypt the properties values i found this thread that answer how do it.