This question already has answers here:
How to do URL decoding in Java?
(11 answers)
How to get the current working directory in Java?
(26 answers)
Closed 2 years ago.
In my program I did
File jarFile = new File(Main.class.getProtectionDomain().getCodeSource().getLocation().getPath());
execPath = String.valueOf(jarFile.getParentFile());
To get the execPath = to the path of the current execution (where the final .exe program is). Wich is an attribute of my main class, that I use to do some files manipulation and reading.
But,
When running the program in some folders with spaces or accents the value of execPath is replaced by %number like bellow
C:\Users\Hugo\OneDrive%20-%20Funda%c3%a7%c3%a3o%20para%20Inova%c3%a7%c3%b5es%20Tecnol%c3%b3gicas%20-%20FITec\Redes\AutoComRouter\
Where
OneDrive%20-%20Funda%c3%a7%c3%a3o%20para%20Inova%c3%a7%c3%b5es%20Tecnol%c3%b3gicas%20-%20FITec
should be
OneDrive - Fundação para Inovações Tecnológicas - FITec
I wonder if its possible to get rid of this annoying replacement for the my execPath attribute.
Do not call the URL.getPath() method. It does not return a valid filename, as you are now seeing. It just returns the path portion of the URL—the part after the scheme and host—with all percent escapes intact.
The correct way to convert a URL to a File is by converting it to a URI, then constructing a File from that URI.
So, the proper code would look like this:
CodeSource source = Main.class.getProtectionDomain().getCodeSource();
if (source != null) {
try {
File jarFile = new File(source.getLocation().toURI());
execPath = String.valueOf(jarFile.getParentFile());
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
Notice the check for null. The code source can be null, depending on how much information a ClassLoader is willing and able to impart to the ProtectionDomain it creates. This means that trying to find the location of a .jar file at runtime is not reliable.
If you want to bundle native executables with a .jar file, here are some more reliable options:
Include a script (batch file for Windows, shell script for other systems) with your .jar file that passes a system property to the program, which contains the location of the executables.
Bundle the executables inside the .jar file, and at runtime, copy them to temporary files and make them executable.
The first approach would use the system to determine the directory, since that is reliable, and would pass it to the program. For instance, in Windows:
set execdir=%~dp0..\..
javaw.exe "-Dexecutable.dir=%here%" -jar MyApplication.jar
In Linux:
execdir=`dirname $0`/..
java "-Dexecutable.dir=$execdir" -jar MyApplication.jar
The second approach would require creating your .jar file with the executables inside it, then copying them outside the .jar when you want to run them:
Path execDir = Files.createTempDirectory(null);
execPath = execDir.toString();
String[] executables;
String os = System.getProperty("os.name");
if (os.contains("Windows")) {
executables = new String[] {
"windows/foo.exe", "windows/bar.exe", "windows/baz.exe"
};
} else if (os.contains("Mac")) {
executables = new String[] {
"mac/foo", "mac/bar", "mac/baz"
};
} else {
executables = new String[] {
"linux/foo", "linux/bar", "linux/baz"
};
}
for (String executable : executables) {
String baseName = executable.substring(executable.lastIndexOf('/') + 1);
Path newFile = execDir.resolve(baseName);
try (InputStream executable =
Main.class.getResourceAsStream(executable)) {
Files.copy(executable, newFile);
}
if (Files.getFileStore(newFile).supportsFileAttributeView(
PosixFileAttributeView.class)) {
Set<PosixFilePermission> perms =
Files.getPosixFilePermissions(newFile);
perms.add(PosixFilePermission.OWNER_EXECUTE);
Files.setPosixFilePermissions(newFile, perms);
}
}
Related
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?
This question already has answers here:
Java Jar file: use resource errors: URI is not hierarchical
(6 answers)
Closed 6 years ago.
I have files in resource folder. For example if I need to get file from resource folder, I do like that:
File myFile= new File(MyClass.class.getResource(/myFile.jpg).toURI());
System.out.println(MyClass.class.getResource(/myFile.jpg).getPath());
I've tested and everything works!
The path is
/D:/java/projects/.../classes/X/Y/Z/myFile.jpg
But, If I create jar file, using , Maven:
mvn package
...and then start my app:
java -jar MyJar.jar
I have that following error:
Exception in thread "Thread-4" java.lang.RuntimeException: ხელმოწერის განხორციელება შეუძლებელია
Caused by: java.lang.IllegalArgumentException: URI is not hierarchical
at java.io.File.<init>(File.java:363)
...and path of file is:
file:/D:/java/projects/.../target/MyJar.jar!/X/Y/Z/myFile.jpg
This exception happens when I try to get file from resource folder. At this line. Why? Why have that problem in JAR file? What do you think?
Is there another way, to get the resource folder path?
You should be using
getResourceAsStream(...);
when the resource is bundled as a jar/war or any other single file package for that matter.
See the thing is, a jar is a single file (kind of like a zip file) holding lots of files together. From Os's pov, its a single file and if you want to access a part of the file(your image file) you must use it as a stream.
Documentation
Here is a solution for Eclipse RCP / Plugin developers:
Bundle bundle = Platform.getBundle("resource_from_some_plugin");
URL fileURL = bundle.getEntry("files/test.txt");
File file = null;
try {
URL resolvedFileURL = FileLocator.toFileURL(fileURL);
// We need to use the 3-arg constructor of URI in order to properly escape file system chars
URI resolvedURI = new URI(resolvedFileURL.getProtocol(), resolvedFileURL.getPath(), null);
File file = new File(resolvedURI);
} catch (URISyntaxException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
It's very important to use FileLocator.toFileURL(fileURL) rather than resolve(fileURL)
, cause when the plugin is packed into a jar this will cause Eclipse to create an unpacked version in a temporary location so that the object can be accessed using File. For instance, I guess Lars Vogel has an error in his article - http://blog.vogella.com/2010/07/06/reading-resources-from-plugin/
I face same issue when I was working on a project in my company. First Of All, The URI is not hierarichal Issue is because probably you are using "/" as file separator.
You must remember that "/" is for Windows and from OS to OS it changes, It may be different in Linux. Hence Use File.seperator .
So using
this.getClass().getClassLoader().getResource("res"+File.separator+"secondFolder")
may remove the URI not hierarichal. But Now you may face a Null Pointer Exception. I tried many different ways and then used JarEntries Class to solve it.
File jarFile = new File(this.getClass().getProtectionDomain().getCodeSource().getLocation().toURI().getPath());
String actualFile = jarFile.getParentFile().getAbsolutePath()+File.separator+"Name_Of_Jar_File.jar";
System.out.println("jarFile is : "+jarFile.getAbsolutePath());
System.out.println("actulaFilePath is : "+actualFile);
final JarFile jar = new JarFile(actualFile);
final Enumeration<JarEntry> entries = jar.entries(); //gives ALL entries in jar
System.out.println("Reading entries in jar file ");
while(entries.hasMoreElements()) {
JarEntry jarEntry = entries.nextElement();
final String name = jarEntry.getName();
if (name.startsWith("Might Specify a folder name you are searching for")) { //filter according to the path
System.out.println("file name is "+name);
System.out.println("is directory : "+jarEntry.isDirectory());
File scriptsFile = new File(name);
System.out.println("file names are : "+scriptsFile.getAbsolutePath());
}
}
jar.close();
You have to specify the jar name here explicitly. So Use this code, this will give you directory and sub directory inside the folder in jar.
I'm trying to unpack/extract an archive, which is supplied in my program, containing binaries.
The copy from within the jar to the file works just fine, but when I try to extract the zip, it returns unexpectedly and only copies half of a file, and ignores the other file completely.
Here's a bit more detailed description:
I'm trying to unzip an archive copied to a folder, from within the program's .jar.
The program I'm using to unzip is "unzip" (comes with Linux).
The command used to extract is:
unzip -o <file>.zip
which is exactly what I'm using in following code:
ProcessBuilder process = new ProcessBuilder();
process.command("unzip", "-o", adb_tools.toString());
process.redirectErrorStream(true);
Process pr = process.start();
String line;
BufferedReader processReader = new BufferedReader(new InputStreamReader(pr.getInputStream()));
while ((line = processReader.readLine()) != null)
log(Level.INFO, "Extracting Android Debugging Bridge: " + line, true);
log(Level.INFO, "Android Debugging Bridge has been extracted and installed to system. Marking files as executable...", true);
pr.destroy();
processReader.close();
When I use the command directly via the Terminal, everything works fine, both files are extracted and inflated, and are executable, however, as mentioned above, when I use the command in Java, only one file gets copied (and even that only goes half way), and the other file is completely ignored.
How can I fix this problem, and prevent this happening again, with different programs?
Thanks in advance!
If you need to do a common task in Java, there is always a library out there which does what you need better than yourself. So use an external library for unzipping. Check here:
What is a good Java library to zip/unzip files?
It looks like you can use zip4j like this (from djangofan's answer):
public static void unzip(){
String source = "some/compressed/file.zip";
String destination = "some/destination/folder";
String password = "password";
try {
ZipFile zipFile = new ZipFile(source);
if (zipFile.isEncrypted()) {
zipFile.setPassword(password);
}
zipFile.extractAll(destination);
} catch (ZipException e) {
e.printStackTrace();
}
}
I would like to use the rar.exe path in Java. This is needed to unpack rar files from within my Java application without using a library.
I figured I'd require the user to add the program files folder for Winrar to the PATH system variable.
All I need to know now is how to get the full path to the rar.exe file.
What I've got now is this:
//Split all paths
String[] paths = System.getenv("Path").split(";");
for(String value : paths)
{
if(value.endsWith("Winrar"))
System.out.println(value);
}
However, there is no way of me knowing if the user installed Winrar to say C:\Programfiles\Winrarstuff. Is there a way to get the location of rar.exe, or do I have to manually scan every folder in the Path string for the location?
You can use where on Windows Server 2003+ which is roughly equivalent to which in *nix, however you can get similar behavior for other windows environments using the code found here: https://stackoverflow.com/a/304441/1427161
When the path to rar.exe is in the PATH environment variable, you can simply invoke rar.exe from any file location. That means you can also call it via Runtime.exec(...). If the return code is other than 0, the process cannot be started, e.g. because Winrar is not installed:
public static boolean checkRar() {
Process proc = Runtime.getRuntime().exec("cmd /c rar.exe");
try (BufferedReader reader =
new BufferedReader(new InputStreamReader(proc.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
// parse line e.g. to get version number
}
}
return (proc.waitFor() == 0);
}
Im trying to write a program to read a text file through args but when i run it, it always says the file can't be found even though i placed it inside the same folder as the main.java that im running.
Does anyone know the solution to my problem or a better way of reading a text file?
Do not use relative paths in java.io.File.
It will become relative to the current working directory which is dependent on the way how you run the application which in turn is not controllable from inside your application. It will only lead to portability trouble. If you run it from inside Eclipse, the path will be relative to /path/to/eclipse/workspace/projectname. If you run it from inside command console, it will be relative to currently opened folder (even though when you run the code by absolute path!). If you run it by doubleclicking the JAR, it will be relative to the root folder of the JAR. If you run it in a webserver, it will be relative to the /path/to/webserver/binaries. Etcetera.
Always use absolute paths in java.io.File, no excuses.
For best portability and less headache with absolute paths, just place the file in a path covered by the runtime classpath (or add its path to the runtime classpath). This way you can get the file by Class#getResource() or its content by Class#getResourceAsStream(). If it's in the same folder (package) as your current class, then it's already in the classpath. To access it, just do:
public MyClass() {
URL url = getClass().getResource("filename.txt");
File file = new File(url.getPath());
InputStream input = new FileInputStream(file);
// ...
}
or
public MyClass() {
InputStream input = getClass().getResourceAsStream("filename.txt");
// ...
}
Try giving an absolute path to the filename.
Also, post the code so that we can see what exactly you're trying.
When you are opening a file with a relative file name in Java (and in general) it opens it relative to the working directory.
you can find the current working directory of your process using
String workindDir = new File(".").getAbsoultePath()
Make sure you are running your program from the correct directory (or change the file name so that it will be relative to where you are running it from).
If you're using Eclipse (or a similar IDE), the problem arises from the fact that your program is run from a few directories above where the actual source is located. Try moving your file up a level or two in the project tree.
Check out this question for more detail.
The simplest solution is to create a new file, then see where the output file is. That is the correct place to put your input file into.
If you put the file and the class working with it under same package can you use this:
Class A {
void readFile (String fileName) {
Url tmp = A.class.getResource (fileName);
// Or Url tmp = this.getClass().getResource (fileName);
File tmpFile = File (tmp);
if (tmpFile.exists())
System.out.print("I found the file.")
}
}
It will help if you read about classloaders.
say I have a text file input.txt which is located on the desktop
and input.txt has the following content
i came
i saw
i left
and below is the java code for reading that text file
public class ReadInputFromTextFile {
public static void main(String[] args) throws Exception
{
File file = new File(
"/Users/viveksingh/desktop/input.txt");
BufferedReader br
= new BufferedReader(new FileReader(file));
String st;
while ((st = br.readLine()) != null)
System.out.println(st);
}
}
output on the console:
i came
i saw
i left