Copying the content of a list into a folder - java

I have an arrayList "rules" containing Rules. Each Rule is an XML file and have some properties such as filename...
I want to copy the Rules from the arraylist to a folder named AllMRG. I tried the code between comments but I get the message "Source 'RG6.31.xml' does not exist".
I changed the code by the following, but there is still a problem with 'RG6.31.xml' and the folder AllMRG is empty even though the arrayList contains many Rules!
First attemption:
File AllMRGFolder = new File("AllMRG");
for(int p = 0; p < rules.size(); p++) {
/* File MRGFile = new File(rules.get(p).fileName);
FileUtils.copyFileToDirectory(MRGFile, AllMRGFolder); */
File MRGFile = new File("AllMRG/" + rules.get(p).fileName);
if (!MRGFile.exists()) {
FileUtils.copyFileToDirectory(MRGFile, AllMRGFolder);
}
}
Second attemption:
String path = "AllMRG";
for(Rule rule : rules) {
File MRGFile = new File(rule.fileName);
Files.copy(MRGFile.toPath(), (new File(path + MRGFile.getName())).toPath(), StandardCopyOption.REPLACE_EXISTING);
}
PS: Rule is a class
public class Rule implements Comparable{
public String fileName;
public String matches;
public String TPinstances;
public int nbrOfMatches;
public double T;
#Override
public int compareTo(Object o) {
if(o instanceof Rule){
//processing to compare one Rule with another
}
return 0;
}
}
Here is the entire code after having considered Shyam's answer. The same problem persists!
Path directoryPath = Files.createDirectory(Paths.get("AllMGR"));
for(Rule rule : rules) {
Path filePath = directoryPath.resolve(rule.fileName);
Files.createFile(filePath);
File MRGFile = new File(rule.fileName);
String ruleContent = new String(Files.readAllBytes(Paths.get(MRGFile.getPath())));
String fileContent = new String(Files.readAllBytes(filePath));
fileContent=ruleContent;
PrintWriter out13= new PrintWriter("AllMGR/"+rule.fileName+".xml");
out13.print(fileContent);
out13.close();
}

Firstly, you are creating a new File with rule.filename without giving any predefined path. Then, you are building a path like: path + MRGFile.getName() without any path delimiters and trying to copy the file to this location. I don't think this will work.
What can actually help you is, creating a base directory first and then creating individual files in it.
Create base directory:
Path directoryPath = Files.createDirectory(Paths.get("AllMGRDir"));
Then for each of your Rule object you can crate file using:
for(Rule rule : rules) {
Path filePath = directoryPath.resolve(rule.fileName());
Files.createFile(filePath);
// your remaining code
}
The resolve(String other) method resolves the given path. Java doc says that:
Converts a given path string to a Path and resolves it against this
Path in exactly the manner specified by the resolve(Path) method.
For example, suppose that the name separator is "/" and a path
represents "foo/bar", then invoking this method with the path string
"gus" will result in the Path "foo/bar/gus"
Hope this helps.

Related

Exclude file extentions for Java based compiler?

I usually find a workaround for problems, but this time I cannot seem to find one.
I am making a compiler for a self-designed language using JavaCC. Before I simply used System.in to read files, so this way I know my compiler can use any text-based file of any extension.
This project must ONLY open files with a custom extension (.bait). From my research, there are plenty of ways in Java to get a file's extension, but they all require a full path. My compiler is supposed to run from any place in the user's disk through a terminal (CMD), so I do not think Java's options are useful.
The question: How can I filter the file extension of a given file that the compiler rejects the source if it's not .bait?
The original code I use is pretty simple:
hook analizador = new hook (System.in);
analizador.RunLexer();
'hook' being the class and RunLexer() is a method for lexical analysis. The code allows any text-based code to be analyzed. For the extention rule I thought of using *.bait regular expresion as in:
hook analizador = new hook (new FileInputStream("*.bait"));
analizador.codigo();
and
InputStream input = new FileInputStream("*.bait");
hook analizador = new hook (input);
with no luck, so far. Can anybody guide me with this? An explanation of the answer will be gladly appreciated.
EDIT: Thanks to sepp2k and MeetTitan.
System.in was not an option, so instead the filename (used as argument) can be used for all the verifications needed:
String arc = args[0];
if(arc.endsWith(".bait")){ //checks file extention
File src = new File(arc); //created just to use exists()
if(src.exists()){
FileReader fr = new FileReader(arc); //used instead of System.in
hook analizador = new hook(fr);
} else System.out.println("File not found");
} else System.out.println("Invalid filetype");
As for the way to use the program, using terminal (CMD)
java hook file.bait
This code doesn't let the user run .bait files out of the hook directory as intended, so it's safe even if there are several copies of the file in different locations.
Hope it can be of any use to someone, and thank you again, sepp2k and MeetTitan!
Why can't you do something like this?
//this method takes a String and returns a substring containing the characters between the last occurrence of '.' and the end of the String
//For example, getExtension("test/your.file.bait"); will return "bait".
public static String getExtension(String fileNameOrPath) {
return fileNameOrPath.substring(fileNameOrPath.lastIndexOf('.')+1);
}
//this method compares equality of "bait" and the returned extension from our other method
public static boolean isBait(String fileNameOrPath) {
return "bait".equals(getExtension(fileNameOrPath));
}
You can use isBait(String) on any path, relative or absolute, or a filename.
You could also simply leverage String.endsWith(String).
Like so:
public static boolean isBait(String str) {
return str.endsWith(".bait");
}
EDIT
To get a listing of all files in a folder with a specific extension, you'd use a FilenameFilter with File.listFiles()
Like so:
File dir = new File("path/to/folder");
File[] baitFiles = dir.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.toLowerCase().endsWith(".bait");
}
});
EDIT to recurse over EVERY subfolder and only get certain files:
public static List<File> recurseGetBait(File dir) { //need method for recursion
List<File> baitFilesList = new ArrayList<>(); //make a new ArrayList that we will populate and return
File[] baitFiles = dir.listFiles(new FilenameFilter() { //get all bait files with previously shown snippet
public boolean accept(File dir, String name) {
return name.toLowerCase().endsWith(".bait");
}
});
for(File baitFile : baitFiles) {
baitFilesList.add(baitFile); //add every file from baitFiles to baitFilesList
}
String[] dirs = file.list(new FilenameFilter() { //get all subfolders of current folder
public boolean accept(File dir, String name) {
return new File(dir, name).isDirectory();
}
});
for(File dir : dirs) { //iterate over all subfolders
List<File> returned = recursiveGetBait(dir); //run this same method on this subfolder (which will recurse until there are no sub folders)
baitFilesList.addAll(returned); // add all of the previously returned bait files to baitFilesList so we populate and return
}
return baitFilesList; //either returns our list to the previous recurse or returns the fully built list to our original caller
}

How to get the location of the program you're running and store it in a File object [duplicate]

Want to improve this post? Provide detailed answers to this question, including citations and an explanation of why your answer is correct. Answers without enough detail may be edited or deleted.
My code runs inside a JAR file, say foo.jar, and I need to know, in the code, in which folder the running foo.jar is.
So, if foo.jar is in C:\FOO\, I want to get that path no matter what my current working directory is.
return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation()
.toURI()).getPath();
Replace "MyClass" with the name of your class.
Obviously, this will do odd things if your class was loaded from a non-file location.
Best solution for me:
String path = Test.class.getProtectionDomain().getCodeSource().getLocation().getPath();
String decodedPath = URLDecoder.decode(path, "UTF-8");
This should solve the problem with spaces and special characters.
To obtain the File for a given Class, there are two steps:
Convert the Class to a URL
Convert the URL to a File
It is important to understand both steps, and not conflate them.
Once you have the File, you can call getParentFile to get the containing folder, if that is what you need.
Step 1: Class to URL
As discussed in other answers, there are two major ways to find a URL relevant to a Class.
URL url = Bar.class.getProtectionDomain().getCodeSource().getLocation();
URL url = Bar.class.getResource(Bar.class.getSimpleName() + ".class");
Both have pros and cons.
The getProtectionDomain approach yields the base location of the class (e.g., the containing JAR file). However, it is possible that the Java runtime's security policy will throw SecurityException when calling getProtectionDomain(), so if your application needs to run in a variety of environments, it is best to test in all of them.
The getResource approach yields the full URL resource path of the class, from which you will need to perform additional string manipulation. It may be a file: path, but it could also be jar:file: or even something nastier like bundleresource://346.fwk2106232034:4/foo/Bar.class when executing within an OSGi framework. Conversely, the getProtectionDomain approach correctly yields a file: URL even from within OSGi.
Note that both getResource("") and getResource(".") failed in my tests, when the class resided within a JAR file; both invocations returned null. So I recommend the #2 invocation shown above instead, as it seems safer.
Step 2: URL to File
Either way, once you have a URL, the next step is convert to a File. This is its own challenge; see Kohsuke Kawaguchi's blog post about it for full details, but in short, you can use new File(url.toURI()) as long as the URL is completely well-formed.
Lastly, I would highly discourage using URLDecoder. Some characters of the URL, : and / in particular, are not valid URL-encoded characters. From the URLDecoder Javadoc:
It is assumed that all characters in the encoded string are one of the following: "a" through "z", "A" through "Z", "0" through "9", and "-", "_", ".", and "*". The character "%" is allowed but is interpreted as the start of a special escaped sequence.
...
There are two possible ways in which this decoder could deal with illegal strings. It could either leave illegal characters alone or it could throw an IllegalArgumentException. Which approach the decoder takes is left to the implementation.
In practice, URLDecoder generally does not throw IllegalArgumentException as threatened above. And if your file path has spaces encoded as %20, this approach may appear to work. However, if your file path has other non-alphameric characters such as + you will have problems with URLDecoder mangling your file path.
Working code
To achieve these steps, you might have methods like the following:
/**
* Gets the base location of the given class.
* <p>
* If the class is directly on the file system (e.g.,
* "/path/to/my/package/MyClass.class") then it will return the base directory
* (e.g., "file:/path/to").
* </p>
* <p>
* If the class is within a JAR file (e.g.,
* "/path/to/my-jar.jar!/my/package/MyClass.class") then it will return the
* path to the JAR (e.g., "file:/path/to/my-jar.jar").
* </p>
*
* #param c The class whose location is desired.
* #see FileUtils#urlToFile(URL) to convert the result to a {#link File}.
*/
public static URL getLocation(final Class<?> c) {
if (c == null) return null; // could not load the class
// try the easy way first
try {
final URL codeSourceLocation =
c.getProtectionDomain().getCodeSource().getLocation();
if (codeSourceLocation != null) return codeSourceLocation;
}
catch (final SecurityException e) {
// NB: Cannot access protection domain.
}
catch (final NullPointerException e) {
// NB: Protection domain or code source is null.
}
// NB: The easy way failed, so we try the hard way. We ask for the class
// itself as a resource, then strip the class's path from the URL string,
// leaving the base path.
// get the class's raw resource path
final URL classResource = c.getResource(c.getSimpleName() + ".class");
if (classResource == null) return null; // cannot find class resource
final String url = classResource.toString();
final String suffix = c.getCanonicalName().replace('.', '/') + ".class";
if (!url.endsWith(suffix)) return null; // weird URL
// strip the class's path from the URL string
final String base = url.substring(0, url.length() - suffix.length());
String path = base;
// remove the "jar:" prefix and "!/" suffix, if present
if (path.startsWith("jar:")) path = path.substring(4, path.length() - 2);
try {
return new URL(path);
}
catch (final MalformedURLException e) {
e.printStackTrace();
return null;
}
}
/**
* Converts the given {#link URL} to its corresponding {#link File}.
* <p>
* This method is similar to calling {#code new File(url.toURI())} except that
* it also handles "jar:file:" URLs, returning the path to the JAR file.
* </p>
*
* #param url The URL to convert.
* #return A file path suitable for use with e.g. {#link FileInputStream}
* #throws IllegalArgumentException if the URL does not correspond to a file.
*/
public static File urlToFile(final URL url) {
return url == null ? null : urlToFile(url.toString());
}
/**
* Converts the given URL string to its corresponding {#link File}.
*
* #param url The URL to convert.
* #return A file path suitable for use with e.g. {#link FileInputStream}
* #throws IllegalArgumentException if the URL does not correspond to a file.
*/
public static File urlToFile(final String url) {
String path = url;
if (path.startsWith("jar:")) {
// remove "jar:" prefix and "!/" suffix
final int index = path.indexOf("!/");
path = path.substring(4, index);
}
try {
if (PlatformUtils.isWindows() && path.matches("file:[A-Za-z]:.*")) {
path = "file:/" + path.substring(5);
}
return new File(new URL(path).toURI());
}
catch (final MalformedURLException e) {
// NB: URL is not completely well-formed.
}
catch (final URISyntaxException e) {
// NB: URL is not completely well-formed.
}
if (path.startsWith("file:")) {
// pass through the URL as-is, minus "file:" prefix
path = path.substring(5);
return new File(path);
}
throw new IllegalArgumentException("Invalid URL: " + url);
}
You can find these methods in the SciJava Common library:
org.scijava.util.ClassUtils
org.scijava.util.FileUtils.
You can also use:
CodeSource codeSource = YourMainClass.class.getProtectionDomain().getCodeSource();
File jarFile = new File(codeSource.getLocation().toURI().getPath());
String jarDir = jarFile.getParentFile().getPath();
Use ClassLoader.getResource() to find the URL for your current class.
For example:
package foo;
public class Test
{
public static void main(String[] args)
{
ClassLoader loader = Test.class.getClassLoader();
System.out.println(loader.getResource("foo/Test.class"));
}
}
(This example taken from a similar question.)
To find the directory, you'd then need to take apart the URL manually. See the JarClassLoader tutorial for the format of a jar URL.
I'm surprised to see that none recently proposed to use Path. Here follows a citation: "The Path class includes various methods that can be used to obtain information about the path, access elements of the path, convert the path to other forms, or extract portions of a path"
Thus, a good alternative is to get the Path objest as:
Path path = Paths.get(Test.class.getProtectionDomain().getCodeSource().getLocation().toURI());
The only solution that works for me on Linux, Mac and Windows:
public static String getJarContainingFolder(Class aclass) throws Exception {
CodeSource codeSource = aclass.getProtectionDomain().getCodeSource();
File jarFile;
if (codeSource.getLocation() != null) {
jarFile = new File(codeSource.getLocation().toURI());
}
else {
String path = aclass.getResource(aclass.getSimpleName() + ".class").getPath();
String jarFilePath = path.substring(path.indexOf(":") + 1, path.indexOf("!"));
jarFilePath = URLDecoder.decode(jarFilePath, "UTF-8");
jarFile = new File(jarFilePath);
}
return jarFile.getParentFile().getAbsolutePath();
}
If you are really looking for a simple way to get the folder in which your JAR is located you should use this implementation.
Solutions like this are hard to find and many solutions are no longer supported, many others provide the path of the file instead of the actual directory. This is easier than other solutions you are going to find and works for java version 1.12.
new File(".").getCanonicalPath()
Gathering the Input from other answers this is a simple one too:
String localPath=new File(getClass().getProtectionDomain().getCodeSource().getLocation().toURI()).getParentFile().getPath()+"\\";
Both will return a String with this format:
"C:\Users\User\Desktop\Folder\"
In a simple and concise line.
I had the the same problem and I solved it that way:
File currentJavaJarFile = new File(Main.class.getProtectionDomain().getCodeSource().getLocation().getPath());
String currentJavaJarFilePath = currentJavaJarFile.getAbsolutePath();
String currentRootDirectoryPath = currentJavaJarFilePath.replace(currentJavaJarFile.getName(), "");
I hope I was of help to you.
Here's upgrade to other comments, that seem to me incomplete for the specifics of
using a relative "folder" outside .jar file (in the jar's same
location):
String path =
YourMainClassName.class.getProtectionDomain().
getCodeSource().getLocation().getPath();
path =
URLDecoder.decode(
path,
"UTF-8");
BufferedImage img =
ImageIO.read(
new File((
new File(path).getParentFile().getPath()) +
File.separator +
"folder" +
File.separator +
"yourfile.jpg"));
For getting the path of running jar file I have studied the above solutions and tried all methods which exist some difference each other. If these code are running in Eclipse IDE they all should be able to find the path of the file including the indicated class and open or create an indicated file with the found path.
But it is tricky, when run the runnable jar file directly or through the command line, it will be failed as the path of jar file gotten from the above methods will give an internal path in the jar file, that is it always gives a path as
rsrc:project-name (maybe I should say that it is the package name of the main class file - the indicated class)
I can not convert the rsrc:... path to an external path, that is when run the jar file outside the Eclipse IDE it can not get the path of jar file.
The only possible way for getting the path of running jar file outside Eclipse IDE is
System.getProperty("java.class.path")
this code line may return the living path (including the file name) of the running jar file (note that the return path is not the working directory), as the java document and some people said that it will return the paths of all class files in the same directory, but as my tests if in the same directory include many jar files, it only return the path of running jar (about the multiple paths issue indeed it happened in the Eclipse).
Other answers seem to point to the code source which is Jar file location which is not a directory.
Use
return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getParentFile();
the selected answer above is not working if you run your jar by click on it from Gnome desktop environment (not from any script or terminal).
Instead, I have fond that the following solution is working everywhere:
try {
return URLDecoder.decode(ClassLoader.getSystemClassLoader().getResource(".").getPath(), "UTF-8");
} catch (UnsupportedEncodingException e) {
return "";
}
I had to mess around a lot before I finally found a working (and short) solution.
It is possible that the jarLocation comes with a prefix like file:\ or jar:file\, which can be removed by using String#substring().
URL jarLocationUrl = MyClass.class.getProtectionDomain().getCodeSource().getLocation();
String jarLocation = new File(jarLocationUrl.toString()).getParent();
For the jar file path:
String jarPath = new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation()
.toURI()).getPath();
For getting the directory path of that jar file:
String dirPath = new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation()
.toURI()).getParent();
The results of the two lines above are like this:
/home/user/MyPrograms/myapp/myjar.jar (value of jarPath)
/home/user/MyPrograms/myapp (value of dirPath)
public static String dir() throws URISyntaxException
{
URI path=Main.class.getProtectionDomain().getCodeSource().getLocation().toURI();
String name= Main.class.getPackage().getName()+".jar";
String path2 = path.getRawPath();
path2=path2.substring(1);
if (path2.contains(".jar"))
{
path2=path2.replace(name, "");
}
return path2;}
Works good on Windows
I tried to get the jar running path using
String folder = MyClassName.class.getProtectionDomain().getCodeSource().getLocation().getPath();
c:\app>java -jar application.jar
Running the jar application named "application.jar", on Windows in the folder "c:\app", the value of the String variable "folder" was "\c:\app\application.jar" and I had problems testing for path's correctness
File test = new File(folder);
if(file.isDirectory() && file.canRead()) { //always false }
So I tried to define "test" as:
String fold= new File(folder).getParentFile().getPath()
File test = new File(fold);
to get path in a right format like "c:\app" instead of "\c:\app\application.jar" and I noticed that it work.
The simplest solution is to pass the path as an argument when running the jar.
You can automate this with a shell script (.bat in Windows, .sh anywhere else):
java -jar my-jar.jar .
I used . to pass the current working directory.
UPDATE
You may want to stick the jar file in a sub-directory so users don't accidentally click it. Your code should also check to make sure that the command line arguments have been supplied, and provide a good error message if the arguments are missing.
Actually here is a better version - the old one failed if a folder name had a space in it.
private String getJarFolder() {
// get name and path
String name = getClass().getName().replace('.', '/');
name = getClass().getResource("/" + name + ".class").toString();
// remove junk
name = name.substring(0, name.indexOf(".jar"));
name = name.substring(name.lastIndexOf(':')-1, name.lastIndexOf('/')+1).replace('%', ' ');
// remove escape characters
String s = "";
for (int k=0; k<name.length(); k++) {
s += name.charAt(k);
if (name.charAt(k) == ' ') k += 2;
}
// replace '/' with system separator char
return s.replace('/', File.separatorChar);
}
As for failing with applets, you wouldn't usually have access to local files anyway. I don't know much about JWS but to handle local files might it not be possible to download the app.?
String path = getClass().getResource("").getPath();
The path always refers to the resource within the jar file.
Try this:
String path = new File("").getAbsolutePath();
This code worked for me to identify if the program is being executed inside a JAR file or IDE:
private static boolean isRunningOverJar() {
try {
String pathJar = Application.class.getResource(Application.class.getSimpleName() + ".class").getFile();
if (pathJar.toLowerCase().contains(".jar")) {
return true;
} else {
return false;
}
} catch (Exception e) {
return false;
}
}
If I need to get the Windows full path of JAR file I am using this method:
private static String getPathJar() {
try {
final URI jarUriPath =
Application.class.getResource(Application.class.getSimpleName() + ".class").toURI();
String jarStringPath = jarUriPath.toString().replace("jar:", "");
String jarCleanPath = Paths.get(new URI(jarStringPath)).toString();
if (jarCleanPath.toLowerCase().contains(".jar")) {
return jarCleanPath.substring(0, jarCleanPath.lastIndexOf(".jar") + 4);
} else {
return null;
}
} catch (Exception e) {
log.error("Error getting JAR path.", e);
return null;
}
}
My complete code working with a Spring Boot application using CommandLineRunner implementation, to ensure that the application always be executed within of a console view (Double clicks by mistake in JAR file name), I am using the next code:
#SpringBootApplication
public class Application implements CommandLineRunner {
public static void main(String[] args) throws IOException {
Console console = System.console();
if (console == null && !GraphicsEnvironment.isHeadless() && isRunningOverJar()) {
Runtime.getRuntime().exec(new String[]{"cmd", "/c", "start", "cmd", "/k",
"java -jar \"" + getPathJar() + "\""});
} else {
SpringApplication.run(Application.class, args);
}
}
#Override
public void run(String... args) {
/*
Additional code here...
*/
}
private static boolean isRunningOverJar() {
try {
String pathJar = Application.class.getResource(Application.class.getSimpleName() + ".class").getFile();
if (pathJar.toLowerCase().contains(".jar")) {
return true;
} else {
return false;
}
} catch (Exception e) {
return false;
}
}
private static String getPathJar() {
try {
final URI jarUriPath =
Application.class.getResource(Application.class.getSimpleName() + ".class").toURI();
String jarStringPath = jarUriPath.toString().replace("jar:", "");
String jarCleanPath = Paths.get(new URI(jarStringPath)).toString();
if (jarCleanPath.toLowerCase().contains(".jar")) {
return jarCleanPath.substring(0, jarCleanPath.lastIndexOf(".jar") + 4);
} else {
return null;
}
} catch (Exception e) {
return null;
}
}
}
Something that is frustrating is that when you are developing in Eclipse MyClass.class.getProtectionDomain().getCodeSource().getLocation() returns the /bin directory which is great, but when you compile it to a jar, the path includes the /myjarname.jar part which gives you illegal file names.
To have the code work both in the ide and once it is compiled to a jar, I use the following piece of code:
URL applicationRootPathURL = getClass().getProtectionDomain().getCodeSource().getLocation();
File applicationRootPath = new File(applicationRootPathURL.getPath());
File myFile;
if(applicationRootPath.isDirectory()){
myFile = new File(applicationRootPath, "filename");
}
else{
myFile = new File(applicationRootPath.getParentFile(), "filename");
}
Not really sure about the others but in my case it didn't work with a "Runnable jar" and i got it working by fixing codes together from phchen2 answer and another from this link :How to get the path of a running JAR file?
The code:
String path=new java.io.File(Server.class.getProtectionDomain()
.getCodeSource()
.getLocation()
.getPath())
.getAbsolutePath();
path=path.substring(0, path.lastIndexOf("."));
path=path+System.getProperty("java.class.path");
Have tried several of the solutions up there but none yielded correct results for the (probably special) case that the runnable jar has been exported with "Packaging external libraries" in Eclipse. For some reason all solutions based on the ProtectionDomain do result in null in that case.
From combining some solutions above I managed to achieve the following working code:
String surroundingJar = null;
// gets the path to the jar file if it exists; or the "bin" directory if calling from Eclipse
String jarDir = new File(ClassLoader.getSystemClassLoader().getResource(".").getPath()).getAbsolutePath();
// gets the "bin" directory if calling from eclipse or the name of the .jar file alone (without its path)
String jarFileFromSys = System.getProperty("java.class.path").split(";")[0];
// If both are equal that means it is running from an IDE like Eclipse
if (jarFileFromSys.equals(jarDir))
{
System.out.println("RUNNING FROM IDE!");
// The path to the jar is the "bin" directory in that case because there is no actual .jar file.
surroundingJar = jarDir;
}
else
{
// Combining the path and the name of the .jar file to achieve the final result
surroundingJar = jarDir + jarFileFromSys.substring(1);
}
System.out.println("JAR File: " + surroundingJar);
The above methods didn't work for me in my Spring environment, since Spring shades the actual classes into a package called BOOT-INF, thus not the actual location of the running file. I found another way to retrieve the running file through the Permissions object which have been granted to the running file:
public static Path getEnclosingDirectory() {
return Paths.get(FileUtils.class.getProtectionDomain().getPermissions()
.elements().nextElement().getName()).getParent();
}
Mention that it is checked only in Windows but i think it works perfect on other Operating Systems [Linux,MacOs,Solaris] :).
I had 2 .jar files in the same directory . I wanted from the one .jar file to start the other .jar file which is in the same directory.
The problem is that when you start it from the cmd the current directory is system32.
Warnings!
The below seems to work pretty well in all the test i have done even
with folder name ;][[;'57f2g34g87-8+9-09!2##!$%^^&() or ()%&$%^##
it works well.
I am using the ProcessBuilder with the below as following:
🍂..
//The class from which i called this was the class `Main`
String path = getBasePathForClass(Main.class);
String applicationPath= new File(path + "application.jar").getAbsolutePath();
System.out.println("Directory Path is : "+applicationPath);
//Your know try catch here
//Mention that sometimes it doesn't work for example with folder `;][[;'57f2g34g87-8+9-09!2##!$%^^&()`
ProcessBuilder builder = new ProcessBuilder("java", "-jar", applicationPath);
builder.redirectErrorStream(true);
Process process = builder.start();
//...code
🍂getBasePathForClass(Class<?> classs):
/**
* Returns the absolute path of the current directory in which the given
* class
* file is.
*
* #param classs
* #return The absolute path of the current directory in which the class
* file is.
* #author GOXR3PLUS[StackOverFlow user] + bachden [StackOverFlow user]
*/
public static final String getBasePathForClass(Class<?> classs) {
// Local variables
File file;
String basePath = "";
boolean failed = false;
// Let's give a first try
try {
file = new File(classs.getProtectionDomain().getCodeSource().getLocation().toURI().getPath());
if (file.isFile() || file.getPath().endsWith(".jar") || file.getPath().endsWith(".zip")) {
basePath = file.getParent();
} else {
basePath = file.getPath();
}
} catch (URISyntaxException ex) {
failed = true;
Logger.getLogger(classs.getName()).log(Level.WARNING,
"Cannot firgue out base path for class with way (1): ", ex);
}
// The above failed?
if (failed) {
try {
file = new File(classs.getClassLoader().getResource("").toURI().getPath());
basePath = file.getAbsolutePath();
// the below is for testing purposes...
// starts with File.separator?
// String l = local.replaceFirst("[" + File.separator +
// "/\\\\]", "")
} catch (URISyntaxException ex) {
Logger.getLogger(classs.getName()).log(Level.WARNING,
"Cannot firgue out base path for class with way (2): ", ex);
}
}
// fix to run inside eclipse
if (basePath.endsWith(File.separator + "lib") || basePath.endsWith(File.separator + "bin")
|| basePath.endsWith("bin" + File.separator) || basePath.endsWith("lib" + File.separator)) {
basePath = basePath.substring(0, basePath.length() - 4);
}
// fix to run inside netbeans
if (basePath.endsWith(File.separator + "build" + File.separator + "classes")) {
basePath = basePath.substring(0, basePath.length() - 14);
}
// end fix
if (!basePath.endsWith(File.separator)) {
basePath = basePath + File.separator;
}
return basePath;
}
This code worked for me:
private static String getJarPath() throws IOException, URISyntaxException {
File f = new File(LicensingApp.class.getProtectionDomain().().getLocation().toURI());
String jarPath = f.getCanonicalPath().toString();
String jarDir = jarPath.substring( 0, jarPath.lastIndexOf( File.separator ));
return jarDir;
}
The getProtectionDomain approach might not work sometimes e.g. when you have to find the jar for some of the core java classes (e.g in my case StringBuilder class within IBM JDK), however following works seamlessly:
public static void main(String[] args) {
System.out.println(findSource(MyClass.class));
// OR
System.out.println(findSource(String.class));
}
public static String findSource(Class<?> clazz) {
String resourceToSearch = '/' + clazz.getName().replace(".", "/") + ".class";
java.net.URL location = clazz.getResource(resourceToSearch);
String sourcePath = location.getPath();
// Optional, Remove junk
return sourcePath.replace("file:", "").replace("!" + resourceToSearch, "");
}
I have another way to get the String location of a class.
URL path = Thread.currentThread().getContextClassLoader().getResource("");
Path p = Paths.get(path.toURI());
String location = p.toString();
The output String will have the form of
C:\Users\Administrator\new Workspace\...
The spaces and other characters are handled, and in the form without file:/. So will be easier to use.

Change files names in parent and child directories

I am a beginner in Java trying to work with Files and Directories. I wanted to create a program where I could change file names automatically while searching through all the child directories for file names that are not valid. I am actually trying to load a huge amount of files on to a server but the server settings do not allow file names containing special characters. To start with I was able to write the code where if I pass the path to a directory it renames all the files with invalid names in that directory:
public class reNaming {
public static String baseLoc = "C:/Users/Developer/Desktop/.../Data Cleanup";
public static void main(String[] args) {
//LinkedList<File> fileList = new LinkedList<File>();
File obj = new File(baseLoc);
int count = 0;
for (File file: obj.listFiles())
{
String origName = file.getName();
if (origName.contains("&") || origName.contains("#") || origName.contains("#"))
{
System.out.println("Original name: "+origName);
origName = origName.replaceAll("&", "_and_");
origName = origName.replaceAll("#", "_at_");
String newName = origName.replaceAll("#", "_");
System.out.println("New Name: "+newName);
String newLoc = baseLoc+"/"+newName;
File newFile = new File(newLoc);
System.out.println(file.renameTo(newFile));
count++;
}
}
}
}
Now I want to do the same but only this time I want all the files to be reNamed even in the child directories. Can somebody please guide me how I can achieve that?
Recursion is your friend
/**Removes 'invalid' characters (&,#,#) from pathnames in the given folder, and subfolders, and returns the number of files renamed*/
public int renameDirectory(File base){
//LinkedList<File> fileList = new LinkedList<File>();
int count=0;//count the renamed files in this directory + its sub. You wanted to do this?
//Process each file in this folder.
for (File file: base.listFiles()){
String origName = file.getName();
File resultFile=file;
if (origName.contains("&") || origName.contains("#") || origName.contains("#")){
//I would replace the if statement with origName.matches(".*[&##].*") or similar, shorter but more error prone.
System.out.println("Original name: "+origName);
origName = origName.replaceAll("&", "_and_");
origName = origName.replaceAll("#", "_at_");
String newName = origName.replaceAll("#", "_");
System.out.println("New Name: "+newName);
String newLoc = baseLoc+File.separator+newName;//having "/" hardcoded is not cross-platform.
File newFile = new File(newLoc);
System.out.println(file.renameTo(newFile));
count++;
resultFile=newFile;//not sure if you could do file=newFile, tired
}
//if this 'file' in the base folder is a directory, process the directory
if(resultFile.isDirectory()){//or similar function
count+=renameDirectory(resultFile);
}
}
return count;
}
Move the code you have to a utility method (e.g. public void renameAll(File f){}). Have a condition that checks if the file is a directory and recursively call your method with it's contents. After that do what you are currently doing.
public void renameAll(File[] files){
for(File f: files){
if(f.isDirectory){
renameAll(f.listFiles());
}
rename(f);
}
}
public void rename(File f){ }

How to get the absolute path of the Jar file? [duplicate]

Want to improve this post? Provide detailed answers to this question, including citations and an explanation of why your answer is correct. Answers without enough detail may be edited or deleted.
My code runs inside a JAR file, say foo.jar, and I need to know, in the code, in which folder the running foo.jar is.
So, if foo.jar is in C:\FOO\, I want to get that path no matter what my current working directory is.
return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation()
.toURI()).getPath();
Replace "MyClass" with the name of your class.
Obviously, this will do odd things if your class was loaded from a non-file location.
Best solution for me:
String path = Test.class.getProtectionDomain().getCodeSource().getLocation().getPath();
String decodedPath = URLDecoder.decode(path, "UTF-8");
This should solve the problem with spaces and special characters.
To obtain the File for a given Class, there are two steps:
Convert the Class to a URL
Convert the URL to a File
It is important to understand both steps, and not conflate them.
Once you have the File, you can call getParentFile to get the containing folder, if that is what you need.
Step 1: Class to URL
As discussed in other answers, there are two major ways to find a URL relevant to a Class.
URL url = Bar.class.getProtectionDomain().getCodeSource().getLocation();
URL url = Bar.class.getResource(Bar.class.getSimpleName() + ".class");
Both have pros and cons.
The getProtectionDomain approach yields the base location of the class (e.g., the containing JAR file). However, it is possible that the Java runtime's security policy will throw SecurityException when calling getProtectionDomain(), so if your application needs to run in a variety of environments, it is best to test in all of them.
The getResource approach yields the full URL resource path of the class, from which you will need to perform additional string manipulation. It may be a file: path, but it could also be jar:file: or even something nastier like bundleresource://346.fwk2106232034:4/foo/Bar.class when executing within an OSGi framework. Conversely, the getProtectionDomain approach correctly yields a file: URL even from within OSGi.
Note that both getResource("") and getResource(".") failed in my tests, when the class resided within a JAR file; both invocations returned null. So I recommend the #2 invocation shown above instead, as it seems safer.
Step 2: URL to File
Either way, once you have a URL, the next step is convert to a File. This is its own challenge; see Kohsuke Kawaguchi's blog post about it for full details, but in short, you can use new File(url.toURI()) as long as the URL is completely well-formed.
Lastly, I would highly discourage using URLDecoder. Some characters of the URL, : and / in particular, are not valid URL-encoded characters. From the URLDecoder Javadoc:
It is assumed that all characters in the encoded string are one of the following: "a" through "z", "A" through "Z", "0" through "9", and "-", "_", ".", and "*". The character "%" is allowed but is interpreted as the start of a special escaped sequence.
...
There are two possible ways in which this decoder could deal with illegal strings. It could either leave illegal characters alone or it could throw an IllegalArgumentException. Which approach the decoder takes is left to the implementation.
In practice, URLDecoder generally does not throw IllegalArgumentException as threatened above. And if your file path has spaces encoded as %20, this approach may appear to work. However, if your file path has other non-alphameric characters such as + you will have problems with URLDecoder mangling your file path.
Working code
To achieve these steps, you might have methods like the following:
/**
* Gets the base location of the given class.
* <p>
* If the class is directly on the file system (e.g.,
* "/path/to/my/package/MyClass.class") then it will return the base directory
* (e.g., "file:/path/to").
* </p>
* <p>
* If the class is within a JAR file (e.g.,
* "/path/to/my-jar.jar!/my/package/MyClass.class") then it will return the
* path to the JAR (e.g., "file:/path/to/my-jar.jar").
* </p>
*
* #param c The class whose location is desired.
* #see FileUtils#urlToFile(URL) to convert the result to a {#link File}.
*/
public static URL getLocation(final Class<?> c) {
if (c == null) return null; // could not load the class
// try the easy way first
try {
final URL codeSourceLocation =
c.getProtectionDomain().getCodeSource().getLocation();
if (codeSourceLocation != null) return codeSourceLocation;
}
catch (final SecurityException e) {
// NB: Cannot access protection domain.
}
catch (final NullPointerException e) {
// NB: Protection domain or code source is null.
}
// NB: The easy way failed, so we try the hard way. We ask for the class
// itself as a resource, then strip the class's path from the URL string,
// leaving the base path.
// get the class's raw resource path
final URL classResource = c.getResource(c.getSimpleName() + ".class");
if (classResource == null) return null; // cannot find class resource
final String url = classResource.toString();
final String suffix = c.getCanonicalName().replace('.', '/') + ".class";
if (!url.endsWith(suffix)) return null; // weird URL
// strip the class's path from the URL string
final String base = url.substring(0, url.length() - suffix.length());
String path = base;
// remove the "jar:" prefix and "!/" suffix, if present
if (path.startsWith("jar:")) path = path.substring(4, path.length() - 2);
try {
return new URL(path);
}
catch (final MalformedURLException e) {
e.printStackTrace();
return null;
}
}
/**
* Converts the given {#link URL} to its corresponding {#link File}.
* <p>
* This method is similar to calling {#code new File(url.toURI())} except that
* it also handles "jar:file:" URLs, returning the path to the JAR file.
* </p>
*
* #param url The URL to convert.
* #return A file path suitable for use with e.g. {#link FileInputStream}
* #throws IllegalArgumentException if the URL does not correspond to a file.
*/
public static File urlToFile(final URL url) {
return url == null ? null : urlToFile(url.toString());
}
/**
* Converts the given URL string to its corresponding {#link File}.
*
* #param url The URL to convert.
* #return A file path suitable for use with e.g. {#link FileInputStream}
* #throws IllegalArgumentException if the URL does not correspond to a file.
*/
public static File urlToFile(final String url) {
String path = url;
if (path.startsWith("jar:")) {
// remove "jar:" prefix and "!/" suffix
final int index = path.indexOf("!/");
path = path.substring(4, index);
}
try {
if (PlatformUtils.isWindows() && path.matches("file:[A-Za-z]:.*")) {
path = "file:/" + path.substring(5);
}
return new File(new URL(path).toURI());
}
catch (final MalformedURLException e) {
// NB: URL is not completely well-formed.
}
catch (final URISyntaxException e) {
// NB: URL is not completely well-formed.
}
if (path.startsWith("file:")) {
// pass through the URL as-is, minus "file:" prefix
path = path.substring(5);
return new File(path);
}
throw new IllegalArgumentException("Invalid URL: " + url);
}
You can find these methods in the SciJava Common library:
org.scijava.util.ClassUtils
org.scijava.util.FileUtils.
You can also use:
CodeSource codeSource = YourMainClass.class.getProtectionDomain().getCodeSource();
File jarFile = new File(codeSource.getLocation().toURI().getPath());
String jarDir = jarFile.getParentFile().getPath();
Use ClassLoader.getResource() to find the URL for your current class.
For example:
package foo;
public class Test
{
public static void main(String[] args)
{
ClassLoader loader = Test.class.getClassLoader();
System.out.println(loader.getResource("foo/Test.class"));
}
}
(This example taken from a similar question.)
To find the directory, you'd then need to take apart the URL manually. See the JarClassLoader tutorial for the format of a jar URL.
I'm surprised to see that none recently proposed to use Path. Here follows a citation: "The Path class includes various methods that can be used to obtain information about the path, access elements of the path, convert the path to other forms, or extract portions of a path"
Thus, a good alternative is to get the Path objest as:
Path path = Paths.get(Test.class.getProtectionDomain().getCodeSource().getLocation().toURI());
The only solution that works for me on Linux, Mac and Windows:
public static String getJarContainingFolder(Class aclass) throws Exception {
CodeSource codeSource = aclass.getProtectionDomain().getCodeSource();
File jarFile;
if (codeSource.getLocation() != null) {
jarFile = new File(codeSource.getLocation().toURI());
}
else {
String path = aclass.getResource(aclass.getSimpleName() + ".class").getPath();
String jarFilePath = path.substring(path.indexOf(":") + 1, path.indexOf("!"));
jarFilePath = URLDecoder.decode(jarFilePath, "UTF-8");
jarFile = new File(jarFilePath);
}
return jarFile.getParentFile().getAbsolutePath();
}
If you are really looking for a simple way to get the folder in which your JAR is located you should use this implementation.
Solutions like this are hard to find and many solutions are no longer supported, many others provide the path of the file instead of the actual directory. This is easier than other solutions you are going to find and works for java version 1.12.
new File(".").getCanonicalPath()
Gathering the Input from other answers this is a simple one too:
String localPath=new File(getClass().getProtectionDomain().getCodeSource().getLocation().toURI()).getParentFile().getPath()+"\\";
Both will return a String with this format:
"C:\Users\User\Desktop\Folder\"
In a simple and concise line.
I had the the same problem and I solved it that way:
File currentJavaJarFile = new File(Main.class.getProtectionDomain().getCodeSource().getLocation().getPath());
String currentJavaJarFilePath = currentJavaJarFile.getAbsolutePath();
String currentRootDirectoryPath = currentJavaJarFilePath.replace(currentJavaJarFile.getName(), "");
I hope I was of help to you.
Here's upgrade to other comments, that seem to me incomplete for the specifics of
using a relative "folder" outside .jar file (in the jar's same
location):
String path =
YourMainClassName.class.getProtectionDomain().
getCodeSource().getLocation().getPath();
path =
URLDecoder.decode(
path,
"UTF-8");
BufferedImage img =
ImageIO.read(
new File((
new File(path).getParentFile().getPath()) +
File.separator +
"folder" +
File.separator +
"yourfile.jpg"));
For getting the path of running jar file I have studied the above solutions and tried all methods which exist some difference each other. If these code are running in Eclipse IDE they all should be able to find the path of the file including the indicated class and open or create an indicated file with the found path.
But it is tricky, when run the runnable jar file directly or through the command line, it will be failed as the path of jar file gotten from the above methods will give an internal path in the jar file, that is it always gives a path as
rsrc:project-name (maybe I should say that it is the package name of the main class file - the indicated class)
I can not convert the rsrc:... path to an external path, that is when run the jar file outside the Eclipse IDE it can not get the path of jar file.
The only possible way for getting the path of running jar file outside Eclipse IDE is
System.getProperty("java.class.path")
this code line may return the living path (including the file name) of the running jar file (note that the return path is not the working directory), as the java document and some people said that it will return the paths of all class files in the same directory, but as my tests if in the same directory include many jar files, it only return the path of running jar (about the multiple paths issue indeed it happened in the Eclipse).
Other answers seem to point to the code source which is Jar file location which is not a directory.
Use
return new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getParentFile();
the selected answer above is not working if you run your jar by click on it from Gnome desktop environment (not from any script or terminal).
Instead, I have fond that the following solution is working everywhere:
try {
return URLDecoder.decode(ClassLoader.getSystemClassLoader().getResource(".").getPath(), "UTF-8");
} catch (UnsupportedEncodingException e) {
return "";
}
I had to mess around a lot before I finally found a working (and short) solution.
It is possible that the jarLocation comes with a prefix like file:\ or jar:file\, which can be removed by using String#substring().
URL jarLocationUrl = MyClass.class.getProtectionDomain().getCodeSource().getLocation();
String jarLocation = new File(jarLocationUrl.toString()).getParent();
For the jar file path:
String jarPath = new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation()
.toURI()).getPath();
For getting the directory path of that jar file:
String dirPath = new File(MyClass.class.getProtectionDomain().getCodeSource().getLocation()
.toURI()).getParent();
The results of the two lines above are like this:
/home/user/MyPrograms/myapp/myjar.jar (value of jarPath)
/home/user/MyPrograms/myapp (value of dirPath)
public static String dir() throws URISyntaxException
{
URI path=Main.class.getProtectionDomain().getCodeSource().getLocation().toURI();
String name= Main.class.getPackage().getName()+".jar";
String path2 = path.getRawPath();
path2=path2.substring(1);
if (path2.contains(".jar"))
{
path2=path2.replace(name, "");
}
return path2;}
Works good on Windows
I tried to get the jar running path using
String folder = MyClassName.class.getProtectionDomain().getCodeSource().getLocation().getPath();
c:\app>java -jar application.jar
Running the jar application named "application.jar", on Windows in the folder "c:\app", the value of the String variable "folder" was "\c:\app\application.jar" and I had problems testing for path's correctness
File test = new File(folder);
if(file.isDirectory() && file.canRead()) { //always false }
So I tried to define "test" as:
String fold= new File(folder).getParentFile().getPath()
File test = new File(fold);
to get path in a right format like "c:\app" instead of "\c:\app\application.jar" and I noticed that it work.
The simplest solution is to pass the path as an argument when running the jar.
You can automate this with a shell script (.bat in Windows, .sh anywhere else):
java -jar my-jar.jar .
I used . to pass the current working directory.
UPDATE
You may want to stick the jar file in a sub-directory so users don't accidentally click it. Your code should also check to make sure that the command line arguments have been supplied, and provide a good error message if the arguments are missing.
Actually here is a better version - the old one failed if a folder name had a space in it.
private String getJarFolder() {
// get name and path
String name = getClass().getName().replace('.', '/');
name = getClass().getResource("/" + name + ".class").toString();
// remove junk
name = name.substring(0, name.indexOf(".jar"));
name = name.substring(name.lastIndexOf(':')-1, name.lastIndexOf('/')+1).replace('%', ' ');
// remove escape characters
String s = "";
for (int k=0; k<name.length(); k++) {
s += name.charAt(k);
if (name.charAt(k) == ' ') k += 2;
}
// replace '/' with system separator char
return s.replace('/', File.separatorChar);
}
As for failing with applets, you wouldn't usually have access to local files anyway. I don't know much about JWS but to handle local files might it not be possible to download the app.?
String path = getClass().getResource("").getPath();
The path always refers to the resource within the jar file.
Try this:
String path = new File("").getAbsolutePath();
This code worked for me to identify if the program is being executed inside a JAR file or IDE:
private static boolean isRunningOverJar() {
try {
String pathJar = Application.class.getResource(Application.class.getSimpleName() + ".class").getFile();
if (pathJar.toLowerCase().contains(".jar")) {
return true;
} else {
return false;
}
} catch (Exception e) {
return false;
}
}
If I need to get the Windows full path of JAR file I am using this method:
private static String getPathJar() {
try {
final URI jarUriPath =
Application.class.getResource(Application.class.getSimpleName() + ".class").toURI();
String jarStringPath = jarUriPath.toString().replace("jar:", "");
String jarCleanPath = Paths.get(new URI(jarStringPath)).toString();
if (jarCleanPath.toLowerCase().contains(".jar")) {
return jarCleanPath.substring(0, jarCleanPath.lastIndexOf(".jar") + 4);
} else {
return null;
}
} catch (Exception e) {
log.error("Error getting JAR path.", e);
return null;
}
}
My complete code working with a Spring Boot application using CommandLineRunner implementation, to ensure that the application always be executed within of a console view (Double clicks by mistake in JAR file name), I am using the next code:
#SpringBootApplication
public class Application implements CommandLineRunner {
public static void main(String[] args) throws IOException {
Console console = System.console();
if (console == null && !GraphicsEnvironment.isHeadless() && isRunningOverJar()) {
Runtime.getRuntime().exec(new String[]{"cmd", "/c", "start", "cmd", "/k",
"java -jar \"" + getPathJar() + "\""});
} else {
SpringApplication.run(Application.class, args);
}
}
#Override
public void run(String... args) {
/*
Additional code here...
*/
}
private static boolean isRunningOverJar() {
try {
String pathJar = Application.class.getResource(Application.class.getSimpleName() + ".class").getFile();
if (pathJar.toLowerCase().contains(".jar")) {
return true;
} else {
return false;
}
} catch (Exception e) {
return false;
}
}
private static String getPathJar() {
try {
final URI jarUriPath =
Application.class.getResource(Application.class.getSimpleName() + ".class").toURI();
String jarStringPath = jarUriPath.toString().replace("jar:", "");
String jarCleanPath = Paths.get(new URI(jarStringPath)).toString();
if (jarCleanPath.toLowerCase().contains(".jar")) {
return jarCleanPath.substring(0, jarCleanPath.lastIndexOf(".jar") + 4);
} else {
return null;
}
} catch (Exception e) {
return null;
}
}
}
Something that is frustrating is that when you are developing in Eclipse MyClass.class.getProtectionDomain().getCodeSource().getLocation() returns the /bin directory which is great, but when you compile it to a jar, the path includes the /myjarname.jar part which gives you illegal file names.
To have the code work both in the ide and once it is compiled to a jar, I use the following piece of code:
URL applicationRootPathURL = getClass().getProtectionDomain().getCodeSource().getLocation();
File applicationRootPath = new File(applicationRootPathURL.getPath());
File myFile;
if(applicationRootPath.isDirectory()){
myFile = new File(applicationRootPath, "filename");
}
else{
myFile = new File(applicationRootPath.getParentFile(), "filename");
}
Not really sure about the others but in my case it didn't work with a "Runnable jar" and i got it working by fixing codes together from phchen2 answer and another from this link :How to get the path of a running JAR file?
The code:
String path=new java.io.File(Server.class.getProtectionDomain()
.getCodeSource()
.getLocation()
.getPath())
.getAbsolutePath();
path=path.substring(0, path.lastIndexOf("."));
path=path+System.getProperty("java.class.path");
Have tried several of the solutions up there but none yielded correct results for the (probably special) case that the runnable jar has been exported with "Packaging external libraries" in Eclipse. For some reason all solutions based on the ProtectionDomain do result in null in that case.
From combining some solutions above I managed to achieve the following working code:
String surroundingJar = null;
// gets the path to the jar file if it exists; or the "bin" directory if calling from Eclipse
String jarDir = new File(ClassLoader.getSystemClassLoader().getResource(".").getPath()).getAbsolutePath();
// gets the "bin" directory if calling from eclipse or the name of the .jar file alone (without its path)
String jarFileFromSys = System.getProperty("java.class.path").split(";")[0];
// If both are equal that means it is running from an IDE like Eclipse
if (jarFileFromSys.equals(jarDir))
{
System.out.println("RUNNING FROM IDE!");
// The path to the jar is the "bin" directory in that case because there is no actual .jar file.
surroundingJar = jarDir;
}
else
{
// Combining the path and the name of the .jar file to achieve the final result
surroundingJar = jarDir + jarFileFromSys.substring(1);
}
System.out.println("JAR File: " + surroundingJar);
The above methods didn't work for me in my Spring environment, since Spring shades the actual classes into a package called BOOT-INF, thus not the actual location of the running file. I found another way to retrieve the running file through the Permissions object which have been granted to the running file:
public static Path getEnclosingDirectory() {
return Paths.get(FileUtils.class.getProtectionDomain().getPermissions()
.elements().nextElement().getName()).getParent();
}
Mention that it is checked only in Windows but i think it works perfect on other Operating Systems [Linux,MacOs,Solaris] :).
I had 2 .jar files in the same directory . I wanted from the one .jar file to start the other .jar file which is in the same directory.
The problem is that when you start it from the cmd the current directory is system32.
Warnings!
The below seems to work pretty well in all the test i have done even
with folder name ;][[;'57f2g34g87-8+9-09!2##!$%^^&() or ()%&$%^##
it works well.
I am using the ProcessBuilder with the below as following:
🍂..
//The class from which i called this was the class `Main`
String path = getBasePathForClass(Main.class);
String applicationPath= new File(path + "application.jar").getAbsolutePath();
System.out.println("Directory Path is : "+applicationPath);
//Your know try catch here
//Mention that sometimes it doesn't work for example with folder `;][[;'57f2g34g87-8+9-09!2##!$%^^&()`
ProcessBuilder builder = new ProcessBuilder("java", "-jar", applicationPath);
builder.redirectErrorStream(true);
Process process = builder.start();
//...code
🍂getBasePathForClass(Class<?> classs):
/**
* Returns the absolute path of the current directory in which the given
* class
* file is.
*
* #param classs
* #return The absolute path of the current directory in which the class
* file is.
* #author GOXR3PLUS[StackOverFlow user] + bachden [StackOverFlow user]
*/
public static final String getBasePathForClass(Class<?> classs) {
// Local variables
File file;
String basePath = "";
boolean failed = false;
// Let's give a first try
try {
file = new File(classs.getProtectionDomain().getCodeSource().getLocation().toURI().getPath());
if (file.isFile() || file.getPath().endsWith(".jar") || file.getPath().endsWith(".zip")) {
basePath = file.getParent();
} else {
basePath = file.getPath();
}
} catch (URISyntaxException ex) {
failed = true;
Logger.getLogger(classs.getName()).log(Level.WARNING,
"Cannot firgue out base path for class with way (1): ", ex);
}
// The above failed?
if (failed) {
try {
file = new File(classs.getClassLoader().getResource("").toURI().getPath());
basePath = file.getAbsolutePath();
// the below is for testing purposes...
// starts with File.separator?
// String l = local.replaceFirst("[" + File.separator +
// "/\\\\]", "")
} catch (URISyntaxException ex) {
Logger.getLogger(classs.getName()).log(Level.WARNING,
"Cannot firgue out base path for class with way (2): ", ex);
}
}
// fix to run inside eclipse
if (basePath.endsWith(File.separator + "lib") || basePath.endsWith(File.separator + "bin")
|| basePath.endsWith("bin" + File.separator) || basePath.endsWith("lib" + File.separator)) {
basePath = basePath.substring(0, basePath.length() - 4);
}
// fix to run inside netbeans
if (basePath.endsWith(File.separator + "build" + File.separator + "classes")) {
basePath = basePath.substring(0, basePath.length() - 14);
}
// end fix
if (!basePath.endsWith(File.separator)) {
basePath = basePath + File.separator;
}
return basePath;
}
This code worked for me:
private static String getJarPath() throws IOException, URISyntaxException {
File f = new File(LicensingApp.class.getProtectionDomain().().getLocation().toURI());
String jarPath = f.getCanonicalPath().toString();
String jarDir = jarPath.substring( 0, jarPath.lastIndexOf( File.separator ));
return jarDir;
}
The getProtectionDomain approach might not work sometimes e.g. when you have to find the jar for some of the core java classes (e.g in my case StringBuilder class within IBM JDK), however following works seamlessly:
public static void main(String[] args) {
System.out.println(findSource(MyClass.class));
// OR
System.out.println(findSource(String.class));
}
public static String findSource(Class<?> clazz) {
String resourceToSearch = '/' + clazz.getName().replace(".", "/") + ".class";
java.net.URL location = clazz.getResource(resourceToSearch);
String sourcePath = location.getPath();
// Optional, Remove junk
return sourcePath.replace("file:", "").replace("!" + resourceToSearch, "");
}
I have another way to get the String location of a class.
URL path = Thread.currentThread().getContextClassLoader().getResource("");
Path p = Paths.get(path.toURI());
String location = p.toString();
The output String will have the form of
C:\Users\Administrator\new Workspace\...
The spaces and other characters are handled, and in the form without file:/. So will be easier to use.

Java equivalent of Perl's File::Spec->catfile? [duplicate]

Is there a Java equivalent for System.IO.Path.Combine() in C#/.NET? Or any code to accomplish this?
This static method combines one or more strings into a path.
Rather than keeping everything string-based, you should use a class which is designed to represent a file system path.
If you're using Java 7 or Java 8, you should strongly consider using java.nio.file.Path; Path.resolve can be used to combine one path with another, or with a string. The Paths helper class is useful too. For example:
Path path = Paths.get("foo", "bar", "baz.txt");
If you need to cater for pre-Java-7 environments, you can use java.io.File, like this:
File baseDirectory = new File("foo");
File subDirectory = new File(baseDirectory, "bar");
File fileInDirectory = new File(subDirectory, "baz.txt");
If you want it back as a string later, you can call getPath(). Indeed, if you really wanted to mimic Path.Combine, you could just write something like:
public static String combine(String path1, String path2)
{
File file1 = new File(path1);
File file2 = new File(file1, path2);
return file2.getPath();
}
In Java 7, you should use resolve:
Path newPath = path.resolve(childPath);
While the NIO2 Path class may seem a bit redundant to File with an unnecessarily different API, it is in fact subtly more elegant and robust.
Note that Paths.get() (as suggested by someone else) doesn't have an overload taking a Path, and doing Paths.get(path.toString(), childPath) is NOT the same thing as resolve(). From the Paths.get() docs:
Note that while this method is very convenient, using it will imply an assumed reference to the default FileSystem and limit the utility of the calling code. Hence it should not be used in library code intended for flexible reuse. A more flexible alternative is to use an existing Path instance as an anchor, such as:
Path dir = ...
Path path = dir.resolve("file");
The sister function to resolve is the excellent relativize:
Path childPath = path.relativize(newPath);
The main answer is to use File objects. However Commons IO does have a class FilenameUtils that can do this kind of thing, such as the concat() method.
platform independent approach (uses File.separator, ie will works depends on operation system where code is running:
java.nio.file.Paths.get(".", "path", "to", "file.txt")
// relative unix path: ./path/to/file.txt
// relative windows path: .\path\to\filee.txt
java.nio.file.Paths.get("/", "path", "to", "file.txt")
// absolute unix path: /path/to/filee.txt
// windows network drive path: \\path\to\file.txt
java.nio.file.Paths.get("C:", "path", "to", "file.txt")
// absolute windows path: C:\path\to\file.txt
I know its a long time since Jon's original answer, but I had a similar requirement to the OP.
By way of extending Jon's solution I came up with the following, which will take one or more path segments takes as many path segments that you can throw at it.
Usage
Path.combine("/Users/beardtwizzle/");
Path.combine("/", "Users", "beardtwizzle");
Path.combine(new String[] { "/", "Users", "beardtwizzle", "arrayUsage" });
Code here for others with a similar problem
public class Path {
public static String combine(String... paths)
{
File file = new File(paths[0]);
for (int i = 1; i < paths.length ; i++) {
file = new File(file, paths[i]);
}
return file.getPath();
}
}
To enhance JodaStephen's answer, Apache Commons IO has FilenameUtils which does this. Example (on Linux):
assert org.apache.commons.io.FilenameUtils.concat("/home/bob", "work\\stuff.log") == "/home/bob/work/stuff.log"
It's platform independent and will produce whatever separators your system needs.
Late to the party perhaps, but I wanted to share my take on this. I prefer not to pull in entire libraries for something like this. Instead, I'm using a Builder pattern and allow conveniently chained append(more) calls. It even allows mixing File and String, and can easily be extended to support Path as well. Furthermore, it automatically handles the different path separators correctly on both Linux, Macintosh, etc.
public class Files {
public static class PathBuilder {
private File file;
private PathBuilder ( File root ) {
file = root;
}
private PathBuilder ( String root ) {
file = new File(root);
}
public PathBuilder append ( File more ) {
file = new File(file, more.getPath()) );
return this;
}
public PathBuilder append ( String more ) {
file = new File(file, more);
return this;
}
public File buildFile () {
return file;
}
}
public static PathBuilder buildPath ( File root ) {
return new PathBuilder(root);
}
public static PathBuilder buildPath ( String root ) {
return new PathBuilder(root);
}
}
Example of usage:
File root = File.listRoots()[0];
String hello = "hello";
String world = "world";
String filename = "warez.lha";
File file = Files.buildPath(root).append(hello).append(world)
.append(filename).buildFile();
String absolute = file.getAbsolutePath();
The resulting absolute will contain something like:
/hello/world/warez.lha
or maybe even:
A:\hello\world\warez.lha
If you do not need more than strings, you can use com.google.common.io.Files
Files.simplifyPath("some/prefix/with//extra///slashes" + "file//name")
to get
"some/prefix/with/extra/slashes/file/name"
Here's a solution which handles multiple path parts and edge conditions:
public static String combinePaths(String ... paths)
{
if ( paths.length == 0)
{
return "";
}
File combined = new File(paths[0]);
int i = 1;
while ( i < paths.length)
{
combined = new File(combined, paths[i]);
++i;
}
return combined.getPath();
}
This also works in Java 8 :
Path file = Paths.get("Some path");
file = Paths.get(file + "Some other path");
This solution offers an interface for joining path fragments from a String[] array. It uses java.io.File.File(String parent, String child):
public static joinPaths(String[] fragments) {
String emptyPath = "";
return buildPath(emptyPath, fragments);
}
private static buildPath(String path, String[] fragments) {
if (path == null || path.isEmpty()) {
path = "";
}
if (fragments == null || fragments.length == 0) {
return "";
}
int pathCurrentSize = path.split("/").length;
int fragmentsLen = fragments.length;
if (pathCurrentSize <= fragmentsLen) {
String newPath = new File(path, fragments[pathCurrentSize - 1]).toString();
path = buildPath(newPath, fragments);
}
return path;
}
Then you can just do:
String[] fragments = {"dir", "anotherDir/", "/filename.txt"};
String path = joinPaths(fragments);
Returns:
"/dir/anotherDir/filename.txt"
Assuming all given paths are absolute paths. you can follow below snippets to merge these paths.
String baseURL = "\\\\host\\testdir\\";
String absoluteFilePath = "\\\\host\\testdir\\Test.txt";;
String mergedPath = Paths.get(baseURL, absoluteFilePath.replaceAll(Matcher.quoteReplacement(baseURL), "")).toString();
output path is \\host\testdir\Test.txt.

Categories

Resources