I am seeing different behavior between Windows, Ubuntu, and Manjaro when creating files. Windows and Manjaro correctly are creating files in the relative path of the jar. However, Ubuntu seems to be creating the files at the user.home location instead.
File file = new File("file.ext");
The files are being created a couple different ways...
// 1 Normal
try (FileOutputStream fos = new FileOutputStream(file);
OutputStreamWriter writer = new OutputStreamWriter(fos, StandardCharsets.UTF_8)) {}
// 2 ImageIO
BufferedImage bufferedImage = ImageIO.read(new URL(imageUrl));
imgFile.createNewFile();
ImageIO.write(bufferedImage, "jpg", imgFile);
// 3 Log4J
<RollingFile name="RollingFile" fileName="./log/output-${date:yyyyMMdd}.log" filePattern="./log/output-%d{yyyyMMdd}.log">
// 4 Sqlite
Connection sqlite = DriverManager.getConnection(String.format("jdbc:sqlite:%s", dbFileName));
All of these files are ending up in the user home in Ubuntu. I've tried the path name plain file.ext and ./file.ext but neither works.
Additional system details:
Ubuntu Desktop 20.04
openjdk version "1.8.0_265"
OpenJDK Runtime Environment (build 1.8.0_265-8u265-bo1-6ubuntu2~20.04-bo1)
OpenIDK 64-Bit Server VM (build 25.265-bo1, mixed mode)
EDIT:
It seems that this happens when running the jar from double click after making it executable chmod +x myproject.jar. It seems that running the jar via terminal java -jar myproject.jar the files appear in the relative path beside the jar.
Something about the executable/double click is causing them to appear in the user.home
Maybe you are on the wrong current directory. May I ask if you did open the terminal of Ubuntu and run the build commands?
new File( "file" ) and new File( "./file" ) both will create the file with the name "file" in the current working directory. What this is depends on various factors, not only on the operating system.
You may call your program (indirectly) through a startup script that sets the current working directory, some operating systems (more specifically, the respective shell) set it either to the program location or to the user's home or use the current directory for it (or think about something else …).
That means that the location for . inside your program depends completely from the execution environment. This in turn means that you should never make any assumptions what this location should be, not even that you can write to it (you may not even be able to read from it).
So yes, your observation is true, but that is expected and well known. And it is no feature (or bug) of Java or any particular JVM, nor is it really an operating system specific, although it may look like.
Related
I'm looking for a way to map every linux directory absolute path to a windows path.
for example: whenever my app is accessing /var/log , it will actually access c:/base-folder/var/log .
My Java app was written in a way that only linux machines can run it. One of the reasons for this constraint is the filesystem paths. I cannot change all paths to a relative paths.
The solution can be in OS level (e.g running from command line cd /var/log will open c:/base-folder/var/log ) or Java level (new File("/var/log") equals to new File("c:/base-folder/var/log") ).
Writing javaagent that changes File and Path classes is not possible, as my app is already running with different javaagent.
Using the built in ubuntu on windows won't work either, because the IDE is on windows.
I need to get the java version from my application that the user has currently installed on their machine. However, the application that I have is installed with a self-contained JRE and when I do a System.getProperty("java.version"), it only returns the version of that self-contained JRE. Is there anyway that I can get the version that is installed on the machine?
The JRE installation are listed in the registry in the key only for Windows, Linux do not have central registry.
HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment
You can make a simple program to test :
public class ShowVersion {
public static void main(String args[]) {
System.out.println(System.getProperty("java.version"));
}
}
Or you can try command prompt
Type java -version
For more you can refer sister site of SO :
https://superuser.com/questions/1221096/how-do-i-check-what-version-of-java-i-have-installed
if you're bundling a JRE (did you check the distribution license for it? Make sure you are allowed to do so) and it's running under that, you get that version back.
If the user were to run it under another JRE, you'd get the version of that JRE. That's just how things work.
In fact if you're using a self-contained JRE the user doesn't even have to have another JRE installed on his system at all, that's the entire point of bundling one in the first place.
Apart from a full file system scan it's impossible to know what other JVMs might be installed, and if you do that you'd have to account for all the different names the Java runtime executables may have depending on the files system you're running on. And after finding all those executables you still have no real way of knowing what version of Java they belong to unless you either do a binary analysis of the executables or somehow detect the information from other files in the directories where those executables are installed, files that may or may not be present depending on the system in question, how it was set up, what JVM is in use, and whether the installation has been manually altered or not.
For example, in the root directory of a JDK installation there is a file called "release" which contains the JVM version, but AFAIK that file isn't required to be there for the JVM to work properly. And your application may not have the rights to the file system to read that file.
You can try looking in known paths e.g. C:\Program Files\Java but unless you scan the entire file system for java or java.exe you will never be sure.
This might not work as expected as in the user that runs your application shouldn't have access to system directories. You can force you application to be started with administrator level access but that would be a security risk.
You requirement seems a bit pointless if you are already bundling a JRE with your application.
You can run cmd command using java (java -version) and use that output to get version.
List<String> cmdArgs = new ArrayList<>();
cmdArgs.add("cmd.exe");
cmdArgs.add("/C");
cmdArgs.add("java -version");
ProcessBuilder processBuilderObj = new ProcessBuilder();
processBuilderObj.command(cmdArgs);
Process process = processBuilderObj.start();
//get inputStream
BufferedReader data = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line1;
while ((line = data.readLine()) != null){
System.out.println(line);
}
While System.getProperty("java.version") returns the version of the Java that your app is running on, calling "java -version" as a system command from your Java app will return the version of the default(installed) Java in your system.
Here are the generic steps to find it programmatically:
Using ProcessBuilder in Java, execute the system command "java -version". This is certainly platform-independent.
Read the output from executed process. The version is usually on the 1st line of the output (smth like java version "1.8.0_191"), so reading the 1st line is enough.
Check using regular expression, if the output matches a string containing a java version, you just parse the version and that will be what you are looking for.
Otherwise, it means the output is an error message (smth like -bash: java: command not found), and there is no Java installed in your system.
control panel
java
Java tab
view
you can see exact version of java used and it's location.
This is a follow-up question to this one (just as a brief description: I have been able to run a Java program by double-clicking on the .jar file on OS X and Windows, but not on Linux, as with the latter I get a file path problem).
Through trying out a few things using NetBeans under Ubuntu (12.04) I found that the problem seems to be located in what the program considers to be its working directory (which I concluded from the output of File.getAbsolutePath()). If I start my application in NetBeans, everything works (even under Ubuntu), and
System.out.println(new File(".").getAbsolutePath());
gives me /home/my_home/projects/VocabTrainer/., which is my project folder and thus correct. However, if I double-click on the .jar file, located in /home/my_home/projects/VocabTrainer/dist, the output I get under Ubuntu suddenly is merely /home/my_home/. This is problematic as I want to access a data file which is located in a sub-directory of my dist dir.
Does anyone know the cause of this behaviour, and how I can solve the problem?
PS: I don't know if this is required, but here's the output of java -version
java version "1.6.0_24"
OpenJDK Runtime Environment (IcedTea6 1.11.5) (6b24-1.11.5-0ubuntu1~12.04.1)
OpenJDK Server VM (build 20.0-b12, mixed mode)
I think you're confusing the location of the JAR with the current working directory.
To determine the former, see How to get the path of a running JAR file?
The cause, not really, at the moment. But you may not want to handle it that way, due to the evident unpredictability. Something like this should get the file, assuming you use the qualified class name of something in the jar in the below getResource call.:
URL url = this.getClass().getClassLoader().getResource("thepackage/ofyourclass/JunkTest.class"); //get url of class file. expected: ("jar:file:/somepath/dist/yourjar.jar!qualified/class/name.class")
File distDir = null;
if(url.getProtocol() == "jar") {
String classPath = null;
String jarPath = url.getPath();
if(jarPath.matches(".*:.*")) jarPath = new URL(jarPath).getPath();
classPath = jarPath.split("!")[0];
distDir = new File(classPath).getParentFile(); //may need to replace / with \ on windows?
} else { //"file" or none
distDir = new File(url.toURI()).getParentFile();
}
//... do what you need to do with distDir to tack on your subdirectory and file name
EDIT: I should point out this is clearly hacky. You may be able to add the file's location to the classpath directly at startup (or include the file you're looking for in the jar). From this you could use this.getClass().getClassLoader().getResource() with the filename of what you're looking for directly, which would get you to something like:
URL url = this.getClass().getResource("yourfile");
File file = new File(url.toURI());
//... use file directly from here
FURTHER EDIT: ok, adapted to your missing protocol, and spread it out, so error messages will be more readable for you.
From Java, I'm extracting an executable into a location specified using File.createTempFile(). When I try to run my executable, my program hangs when it tries to read the first line of output.
I have discovered that if I try to run the same extracted executable from another program, it works if I specify the directory as C:\Documents and Settings\username\Local Settings\Temp\prog.exe. But if I specify the directory as C:\DOCUME~1\USERNA~1\LOCALS~1\Temp\prog.exe I get the hang.
Is there a way to unmangle the tilde filename in my program so I can specify a directory name that will work?
(And since I always like addressing the language and API design issues, is there any reason why Java File.createTempFile() and java.io.tmpdir have to evaluate to mangled filenames?)
You can use getCanonicalPath() to get the expanded path. E.g.:
try
{
File file = File.createTempFile("abc", null);
System.out.println(file.getPath());
System.out.println(file.getCanonicalPath());
}
catch (IOException e) {}
... produces ...
C:\DOCUME~1\USERNA~1\LOCALS~1\Temp\abc49634.tmp
C:\Documents and Settings\username\Local Settings\Temp\abc49634.tmp
I tested this on XP, but assume it would work similarly on other Windows operating systems.
See #raviaw's answer to your second question.
Wow, I never saw that. The fact is that the environment variable %TEMP% returns a mangled name (this is from my computer):
TEMP=C:\DOCUME~1\raviw\LOCALS~1\Temp
TMP=C:\DOCUME~1\raviw\LOCALS~1\Temp
Assuming that a newly create java VM uses the environment variable to get the temporary folder location, it is not VM's fault that the directories are coming mangled.
And even if you try to use System.getenv() to get the temporary folder, you will still have the same problem.
I would make sure that:
The problem is not caused by the fact that you have a directory called "prog.exe" (based on your question, I am assuming this);
If the file is "prog.exe", if it was not in use by any other program (an antivirus, maybe);
Checking if your computer is sane (this would be a very critical bug for any application that is not a web application and that need temporary files).
Synopsis: When calling an executable that links to shared libraries from Java code on Tomcat, I get errors on Windows 2003 whereas the executable works great on a command prompt.
I wanted to do this in Linux, but, alas, got outvoted and have to implement it using Windows Server 2003. Here it goes,
I have a simple Java code running on Tomcat which, when it receives a "start" signal from another server has to run an external executable (written in C++, using shared library DLLs from OpenCV and ffmpeg) like so
String cmd = "c:\\workspace\\process_video.exe -video " + filename;
// Execute the command
Process proc = null;
try {
proc = rt.exec(cmd);
} catch (Exception e) {
System.out.println("VA-> Exception thrown in running the command!");
errorOut.append(e.getStackTrace().toString());
}
Now, when I run the command in process_video from a DOS command prompt, it works (doesn't matter which directory it's issued from). However, when it is run through the Tomcat->my Java code->rt.exec() chain, cmd doesn't get executed, although the exception doesn't get thrown. When I examine Windows event logs, I see an APPCHRASH event for process_video with Fault Module Name cv110.dll, which is one of the OpenCV DLLs I link from cmd.
One solution would be to stuff all the DLLs used in process_video into the tomcat\lib directory, but this hurts my programmatic sensibilities, so I want to know if there is a better way to solve this issue. What user does Tomcat use when running executables on Windows? Maybe I can give more privileges to that user? Should I add the DLL paths to Tomcat's configuration file?
Any help will be much appreciated,
Thanks!
Cuneyt
Add an entry in the PATH evironment variable that points to where your DLLs are. If this doesn't work for your app, you can try adding the entry to Tomcat's PATH. You have to modify the PATH variable of the process that will be loading the executable. Since your Java code probably shares a JVM (and hence a process) with the Tomcat executable, that will dictate which environment the PATH variable will need to be updated.
This is a Windows problem, not a Tomcat problem.
By default, Windows looks in %Path% for DLLs, which may not include the directory of the EXE file.
You can fix this by creating an empty file called process_video.exe.local in the same direcotry as the EXE ( i.e. c:\workspace )
You can also create a .manifest file, but this is a bit more complicated.