Get normalized path for windows location in Java - java

I have a requirement where I have a path as C:\..\bar
for this the file bar gets created in the C drive when I use this path in SQL server.
Now on using Apache's FilenameUtils, The normalize method returns null as also documented.
C:\..\bar --> null
But I want
C:\bar for C:\..\bar
Is there any way in Java to get C:\bar for C:\..\bar
I know that .. would mean parent directory but SQL server still creates file the C drive.
The issue with using File or Path classes is that they make use of underlying Filesystem, which in my case is Unix but the path I will get will be windows absolute path.
So basically want to get rid of any redundancy like dots and slashes irrespective of the file system.

You can use getCanonicalFile.
import java.io.File;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
File file = new File("C:\\..\\bar");
System.out.println(file.getCanonicalPath());
}
}

Related

How to change the user.dir in java 8? [duplicate]

How can I change the current working directory from within a Java program? Everything I've been able to find about the issue claims that you simply can't do it, but I can't believe that that's really the case.
I have a piece of code that opens a file using a hard-coded relative file path from the directory it's normally started in, and I just want to be able to use that code from within a different Java program without having to start it from within a particular directory. It seems like you should just be able to call System.setProperty( "user.dir", "/path/to/dir" ), but as far as I can figure out, calling that line just silently fails and does nothing.
I would understand if Java didn't allow you to do this, if it weren't for the fact that it allows you to get the current working directory, and even allows you to open files using relative file paths....
There is no reliable way to do this in pure Java. Setting the user.dir property via System.setProperty() or java -Duser.dir=... does seem to affect subsequent creations of Files, but not e.g. FileOutputStreams.
The File(String parent, String child) constructor can help if you build up your directory path separately from your file path, allowing easier swapping.
An alternative is to set up a script to run Java from a different directory, or use JNI native code as suggested below.
The relevant OpenJDK bug was closed in 2008 as "will not fix".
If you run your legacy program with ProcessBuilder, you will be able to specify its working directory.
There is a way to do this using the system property "user.dir". The key part to understand is that getAbsoluteFile() must be called (as shown below) or else relative paths will be resolved against the default "user.dir" value.
import java.io.*;
public class FileUtils
{
public static boolean setCurrentDirectory(String directory_name)
{
boolean result = false; // Boolean indicating whether directory was set
File directory; // Desired current working directory
directory = new File(directory_name).getAbsoluteFile();
if (directory.exists() || directory.mkdirs())
{
result = (System.setProperty("user.dir", directory.getAbsolutePath()) != null);
}
return result;
}
public static PrintWriter openOutputFile(String file_name)
{
PrintWriter output = null; // File to open for writing
try
{
output = new PrintWriter(new File(file_name).getAbsoluteFile());
}
catch (Exception exception) {}
return output;
}
public static void main(String[] args) throws Exception
{
FileUtils.openOutputFile("DefaultDirectoryFile.txt");
FileUtils.setCurrentDirectory("NewCurrentDirectory");
FileUtils.openOutputFile("CurrentDirectoryFile.txt");
}
}
It is possible to change the PWD, using JNA/JNI to make calls to libc. The JRuby guys have a handy java library for making POSIX calls called jnr-posix. Here's the maven info
As mentioned you can't change the CWD of the JVM but if you were to launch another process using Runtime.exec() you can use the overloaded method that lets you specify the working directory. This is not really for running your Java program in another directory but for many cases when one needs to launch another program like a Perl script for example, you can specify the working directory of that script while leaving the working dir of the JVM unchanged.
See Runtime.exec javadocs
Specifically,
public Process exec(String[] cmdarray,String[] envp, File dir) throws IOException
where dir is the working directory to run the subprocess in
If I understand correctly, a Java program starts with a copy of the current environment variables. Any changes via System.setProperty(String, String) are modifying the copy, not the original environment variables. Not that this provides a thorough reason as to why Sun chose this behavior, but perhaps it sheds a little light...
The working directory is a operating system feature (set when the process starts).
Why don't you just pass your own System property (-Dsomeprop=/my/path) and use that in your code as the parent of your File:
File f = new File ( System.getProperty("someprop"), myFilename)
The smarter/easier thing to do here is to just change your code so that instead of opening the file assuming that it exists in the current working directory (I assume you are doing something like new File("blah.txt"), just build the path to the file yourself.
Let the user pass in the base directory, read it from a config file, fall back to user.dir if the other properties can't be found, etc. But it's a whole lot easier to improve the logic in your program than it is to change how environment variables work.
I have tried to invoke
String oldDir = System.setProperty("user.dir", currdir.getAbsolutePath());
It seems to work. But
File myFile = new File("localpath.ext");
InputStream openit = new FileInputStream(myFile);
throws a FileNotFoundException though
myFile.getAbsolutePath()
shows the correct path.
I have read this. I think the problem is:
Java knows the current directory with the new setting.
But the file handling is done by the operation system. It does not know the new set current directory, unfortunately.
The solution may be:
File myFile = new File(System.getPropety("user.dir"), "localpath.ext");
It creates a file Object as absolute one with the current directory which is known by the JVM. But that code should be existing in a used class, it needs changing of reused codes.
~~~~JcHartmut
You can use
new File("relative/path").getAbsoluteFile()
after
System.setProperty("user.dir", "/some/directory")
System.setProperty("user.dir", "C:/OtherProject");
File file = new File("data/data.csv").getAbsoluteFile();
System.out.println(file.getPath());
Will print
C:\OtherProject\data\data.csv
You can change the process's actual working directory using JNI or JNA.
With JNI, you can use native functions to set the directory. The POSIX method is chdir(). On Windows, you can use SetCurrentDirectory().
With JNA, you can wrap the native functions in Java binders.
For Windows:
private static interface MyKernel32 extends Library {
public MyKernel32 INSTANCE = (MyKernel32) Native.loadLibrary("Kernel32", MyKernel32.class);
/** BOOL SetCurrentDirectory( LPCTSTR lpPathName ); */
int SetCurrentDirectoryW(char[] pathName);
}
For POSIX systems:
private interface MyCLibrary extends Library {
MyCLibrary INSTANCE = (MyCLibrary) Native.loadLibrary("c", MyCLibrary.class);
/** int chdir(const char *path); */
int chdir( String path );
}
The other possible answer to this question may depend on the reason you are opening the file. Is this a property file or a file that has some configuration related to your application?
If this is the case you may consider trying to load the file through the classpath loader, this way you can load any file Java has access to.
If you run your commands in a shell you can write something like "java -cp" and add any directories you want separated by ":" if java doesnt find something in one directory it will go try and find them in the other directories, that is what I do.
Use FileSystemView
private FileSystemView fileSystemView;
fileSystemView = FileSystemView.getFileSystemView();
currentDirectory = new File(".");
//listing currentDirectory
File[] filesAndDirs = fileSystemView.getFiles(currentDirectory, false);
fileList = new ArrayList<File>();
dirList = new ArrayList<File>();
for (File file : filesAndDirs) {
if (file.isDirectory())
dirList.add(file);
else
fileList.add(file);
}
Collections.sort(dirList);
if (!fileSystemView.isFileSystemRoot(currentDirectory))
dirList.add(0, new File(".."));
Collections.sort(fileList);
//change
currentDirectory = fileSystemView.getParentDirectory(currentDirectory);

How does Java resolve a relative path in new File()?

I am trying to understand the way Java resolves relative path in while creating a File object.
OS used: Windows
For the below snippet, I am getting an IOException as it cannot find the path:
#Test
public void testPathConversion() {
File f = new File("test/test.txt");
try {
f.createNewFile();
System.out.println(f.getPath());
System.out.println(f.getAbsolutePath());
System.out.println(f.getCanonicalPath());
} catch (Exception e) {
e.printStackTrace();
}
}
My understanding here is, Java treats the path provided as absolute and returns an error when the path does not exist. So it makes sense.
When I update the above code to use relative path:
#Test
public void testPathConversion() {
File f = new File("test/../test.txt");
try {
f.createNewFile();
System.out.println(f.getPath());
System.out.println(f.getAbsolutePath());
System.out.println(f.getCanonicalPath());
} catch (Exception e) {
e.printStackTrace();
}
}
It creates a new file and provides the below output:
test\..\test.txt
C:\JavaForTesters\test\..\test.txt
C:\JavaForTesters\test.txt
In this case, my assumption is, even though the path provided doesn't exist, because the path contains "/../", java treats this as a relative path and creates the file in the user.dir. So this also makes sense.
But if I update the relative path as below:
#Test
public void testPathConversion() {
File f = new File("test/../../test.txt");
try {
f.createNewFile();
System.out.println(f.getPath());
System.out.println(f.getAbsolutePath());
System.out.println(f.getCanonicalPath());
} catch (Exception e) {
e.printStackTrace();
}
}
Then I get IOException: Access is denied.
My questions are:
why "test/../test.txt" is treated as a relative path and creates the file in "user.dir" but"test/../../test.txt" returns an error? Where does it attempt to create the file for the path "test/../../test.txt"?
When the specified relative path is not found, the file seems to be created in the user.dir. So, it appears to me that the below two scenarios does the same thing:
//scenario 1
File f = new File("test/../test.txt");
f.createNewFile();
//scenario 2
File f = new File("test.txt");
f.createNewFile();
So is there a real world case where one would use scenario 1 instead of scenario 2?
I suppose I am missing something obvious here or have fundamentally misunderstood relative paths. I went through the Java docs for File and I am not able to find an explanation for this. There are quite a few questions posted in Stack Overflow regarding relative paths, but the ones I looked up were for specific scenarios and not exactly about how relative paths are resolved.
It will be great if someone could please explain me how this works or point to some related links?
There is a concept of a working directory.
This directory is represented by a . (dot).
In relative paths, everything else is relative to it.
Simply put the . (the working directory) is where you run your program.
In some cases the working directory can be changed but in general this is
what the dot represents. I think this is C:\JavaForTesters\ in your case.
So test\..\test.txt means: the sub-directory test
in my working directory, then one level up, then the
file test.txt. This is basically the same as just test.txt.
For more details check here.
http://docs.oracle.com/javase/7/docs/api/java/io/File.html
http://docs.oracle.com/javase/tutorial/essential/io/pathOps.html
When your path starts with a root dir i.e. C:\ in windows or / in Unix or in java resources path, it is considered to be an absolute path. Everything else is relative, so
new File("test.txt") is the same as new File("./test.txt")
new File("test/../test.txt") is the same as new File("./test/../test.txt")
The major difference between getAbsolutePath and getCanonicalPath is that the first one concatenates a parent and a child path, so it may contain dots: .. or .. getCanonicalPath will always return the same path for a particular file.
Note: File.equals uses an abstract form of a path (getAbsolutePath) to compare files, so this means that two File objects for the same might not be equal and Files are unsafe to use in collections like Map or Set.
The working directory is a common concept across virtually all operating systems and program languages etc. It's the directory in which your program is running. This is usually (but not always, there are ways to change it) the directory the application is in.
Relative paths are ones that start without a drive specifier. So in linux they don't start with a /, in windows they don't start with a C:\, etc. These always start from your working directory.
Absolute paths are the ones that start with a drive (or machine for network paths) specifier. They always go from the start of that drive.
Relative paths can be best understood if you know how Java runs the program.
There is a concept of working directory when running programs in Java. Assuming you have a class, say, FileHelper that does the IO under
/User/home/Desktop/projectRoot/src/topLevelPackage/.
Depending on the case where you invoke java to run the program, you will have different working directory. If you run your program from within and IDE, it will most probably be projectRoot.
In this case $ projectRoot/src : java topLevelPackage.FileHelper it will be src.
In this case $ projectRoot : java -cp src topLevelPackage.FileHelper it will be projectRoot.
In this case $ /User/home/Desktop : java -cp ./projectRoot/src topLevelPackage.FileHelper it will be Desktop.
(Assuming $ is your command prompt with standard Unix-like FileSystem. Similar correspondence/parallels with Windows system)
So, your relative path root (.) resolves to your working directory. Thus to be better sure of where to write files, it's said to consider below approach.
package topLevelPackage
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
public class FileHelper {
// Not full implementation, just barebone stub for path
public void createLocalFile() {
// Explicitly get hold of working directory
String workingDir = System.getProperty("user.dir");
Path filePath = Paths.get(workingDir+File.separator+"sampleFile.txt");
// In case we need specific path, traverse that path, rather using . or ..
Path pathToProjectRoot = Paths.get(System.getProperty("user.home"), "Desktop", "projectRoot");
System.out.println(filePath);
System.out.println(pathToProjectRoot);
}
}
Hope this helps.
On windows and Netbeans you can set the relative path as:
new FileReader("src\\PACKAGE_NAME\\FILENAME");
On Linux and Netbeans you can set the relative path as:
new FileReader("src/PACKAGE_NAME/FILENAME");
If you have your code inside Source Packages
I do not know if it is the same for eclipse or other IDE
Only slightly related to the question, but try to wrap your head around this one. So un-intuitive:
import java.nio.file.*;
class Main {
public static void main(String[] args) {
Path p1 = Paths.get("/personal/./photos/./readme.txt");
Path p2 = Paths.get("/personal/index.html");
Path p3 = p1.relativize(p2);
System.out.println(p3); //prints ../../../../index.html !!
}
}
I went off of peter.petrov's answer but let me explain where you make the file edits to change it to a relative path.
Simply edit "AXLAPIService.java" and change
url = new URL("file:C:users..../schema/current/AXLAPI.wsdl");
to
url = new URL("file:./schema/current/AXLAPI.wsdl");
or where ever you want to store it.
You can still work on packaging the wsdl file into the meta-inf folder in the jar but this was the simplest way to get it working for me.

Java - FilenotfoundException for reading text file

by running this...
File file = new File("Highscores.scr");
i keep getting this error, and i really don't know how to get around it.
the file is currently sitting in my source packages with my .java files.
I can quite easily read the file by specifying the path but i intend to run this on multiple computers so i need the file to be portable with the program.
this question isnt about reading the text file but rather specifying its location without using an absolute path .
ive searched for the answer but the answers i get are just "specify the name" and "specify the absolute path".
id post an image to make it more clear but i dont have the 10 rep to do so :/
how do i do this?
cheers.
The best way to do this is to put it in your classpath then getResource()
package com.sandbox;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
public class Sandbox {
public static void main(String[] args) throws URISyntaxException, IOException {
new Sandbox().run();
}
private void run() throws URISyntaxException, IOException {
URL resource = Sandbox.class.getResource("/my.txt");
File file = new File(resource.toURI());
String s = FileUtils.readFileToString(file);
System.out.println(s);
}
}
I'm doing this because I'm assuming you need a File. But if you have an api which takes an InputStream instead, it's probably better to use getResourceAsStream instead.
Notice the path, /my.txt. That means, "get a file named my.txt that is in the root directory of the classpath". I'm sure you can read more about getResource and getResourceAsStream to learn more about how to do this. But the key thing here is that the classpath for the file will be the same for any computer you give the executable to (as long as you don't move the file around in your classpath).
BTW, if you get a null pointer exception on the line that does new File, that means that you haven't specified the correct classpath for the file.
As far as I remember the default directory with be the same as your project folder level. Put the file one level higher.
-Project/
----src/
----test/
-Highscores.scr
If you are building your code on your eclipse then you need to put your Highscores.scr to your project folder. Try that and check.
You can try to run the following sample program to check which is the current directory your program is picking up.
File f = new File(".");
System.out.println("Current Directory is: " + f.getAbsolutePath());

How to determine the path to the file that starts the application in java

i want to ask you regardless finding the file path...
I have, or i would have files that will be associated with my app, but i dont know how to find out the file path that initializes opening my app.
For example:
If i click in windows enviroment on excel file "file.xlx", windows will open excel application with this file "file.xls" and i want exactly the same. After my app will be open, i want to know file path that inicializes my app to start...
I hope that my question is understandable and i apologize for my bad english.. :)
Edit:
I try add some another example...
I try describe some logic operations...
1 - nothing is running, only windows - i hope :)
2 - user click on some file that is somewhere in the HDD ( this file can have different name and different location )
3 - this file with some extension has associated start with my app
4 - app automatically find out on whitch file user clicked ( who invoke the launch of my application ) and use this file path on other work...
I think that should be something like when i start console app. with some argument....but this argument i must get from some windows location.
Just like when i click on file.txt and windows will open notepad and notepad will have automatically open this file.txt, or i click on file.dbf and windows will open the foxpro with this file
I want click on file.xxx and my app will open and work with this file automatically, so there i think must be some way how to get this file location on which i clicked...
I hope this help...
Look at the java system properties http://docs.oracle.com/javase/tutorial/essential/environment/sysprop.html, you probably want user.dir
i think what you need is a program like this , this will calculate the existance of your file in side the given directory
package fileSearch;
import java.io.File;
import java.io.FilenameFilter;
public class fileSearch {
/**
* #param args
*/
public static void main(String[] args) {
fileSearch obj = new fileSearch();
obj.finder("program.txt");
for(int i=0;i<obj.finder("C:/Users/hussain.a/Desktop").length;i++)
{
System.out.println(obj.finder("C:/Users/hussain.a/Desktop")[i].getName());
}
}
public File[] finder( String dirName){
File dir = new File(dirName);
return dir.listFiles(new FilenameFilter() {
public boolean accept(File dir, String filename)
{ return filename.endsWith(".txt"); }
} );
}
}
now its up to you to apply to your desired directory , if you want it to exactly like the windows program , then you will have to use root directory every time and pass the file name as a parameter replacing ".txt" in this program
hope it serves , rest is up to you to implement it
I think you can set the os,like the registry,when you installing the app.
String osName = System.getProperty("os.name") ;

Unable to read a directory using File.list()

I was hoping to get a list of all files and folders in a directory using java without using system calls.
I tried:
import java.io.File;
import java.util.Arrays;
public class test {
/**
* #param args
*/
public static void main(String[] args) {
File fileDir = new File("directory");
String[] fileNames = fileDir.list();
System.out.println(Arrays.toString(fileDir.list()));
}
}
But it only returned 9 files out of many more. I tried with a Perl script and got the same result. I think there is something wrong with the directory, but I'm at a loss as to what.
I would really appreciate some help.
You are probably looking at wrong directory -> mind you are using relative path, which might be different than what you expect (print out fileDir.getAbsolutePath() to find out).
Declaring a file object pointing at "directory" means that the file object will end up pointing to <jvm running directory>/directory . The jvm running directory is generally whatever directory you launch the jvm from. Try using the full path to the directory and see if it works.
Otherwise, please provide some sample output as well as the expected output.

Categories