What exactly does it mean to "resolve" a path? - java

I've now read numerous articles on the use of Java somePath.resolve( someOtherPath ) but I can't find a precise definition, with helpful examples, of what exactly "resolving" a Path means. Everyone seems to assume you know.
Can someone define it non-circularly? Or point me to a (non-circular) explainer?

The answer to this is defined in the documentation, which does a great job of indicating what the method does.
Converts a given path string to a Path and resolves it against this Path in exactly the manner specified by the resolve 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".
In other words, if the path C:/Program Files/Foo/ is the current Path and Bar exists in Foo, you could do the following:
Path parent = Paths.get("C:", "Program Files", "Foo");
Path child = parent.resolve("Bar");

Jason's answer is complete, but on the off chance you're looking for an even simpler answer/example..
I would say the "resolve" method that you specificaly referred to (which starts at somePath) starts at a certain Path, somePath, and then tells you what would happen if you choose to go to someOtherPath but specifically starting at somePath.
So if you had a directory structure on a PC, for example, like this:
C:
- FolderA
- Folder1
- FolderB
- Folder1
If you resolved someOtherPath as "Folder1", then it would depend where you started...
If your somePath was "/FolderA" then you'd end up at "C:/FolderA/Folder1"
If your somePath was "/FolderB" then you'd end up at "C:/FolderB/Folder1"
If your somePath was "/" (the root), then you'd have an invalid path...

Related

moving File leads to file with path separator "/" in filename

I try to move a file from one directory to another.
I do this with
File fileToMove = new File("/Users/kai-dj/separator_problem/from/file_to_move.file");
File destDir = new File("/Users/kai-dj/separator_problem/to");
if (fileToMove.exists() && destDir.isDirectory()) {
fileToMove.renameTo(new File(destDir.getAbsolutePath()+File.pathSeparator+fileToMove.getName()));
}
I'd expect to find file_to_move.file in folder /Users/kai-dj/separator_problem/to after execution, but I get a file named to/file_to_move.file placed in the parent folder /Users/kai-dj/separator_problem. At least that's what Finder shows.
As I thought: "File names mustn't contain path separator characters, this can't be true.", I also checked what ls would output in terminal:
mac-book:separator_problem kai-dj$ ls
from to:file_to_move.file
to
OK – seems no /in file name. Very strange nontheless.
Why does Finder show it as file name containing /?
Why does Java rename the file to <dirname>:<filename> – especially even when I used File.pathSeparator, not / and certainly not :?
I also tried with Files.move – same result.
EDIT: Solved, but I'd still love to know, why Finder shows : as / ^^
As mentioned in the comment above, the correct member to use is called File.separator.
Also, you can avoid using File.separator in general, and use Paths instead:
System.out.println(Paths.get("/Users/kai-dj/separator_problem/to", fileToMove.getName()).toAbsolutePath());

How to program relative path from string in Java

I have the following problem. I am writing a program that imitates Windows Command prompt. For example user enters: cd C:\\Intel and in my code I solve it like this:
setCurrentPath(Paths.get(string));
where setCurrentPath is a method which sets the current path to the one which is entered (string). My problem is that, how can I set new path if the entered path is relative. For example, if I am currently in C:\\Intel and user wants to go to C:\\Intel\\Logs and enters: cd Logs (instead of C:\\Intel\\Logs). I suppose there are some methods build in Java which can help me out but I am learning Java only a few months so I am unaware of them. Be aware that I threat path as a string.
You could test if path from user is absolute or not and based on result either set it directly, or use Path.resolve.
DEMO:
Path currentPath = Paths.get("C:\\projects\\project1");
String pathFromUser = "..\\project2";
Path userPath = Paths.get(pathFromUser);
if (userPath.isAbsolute()){
currentPath = userPath;
}else{//is relative
currentPath = currentPath.resolve(userPath).normalize();
}
System.out.println(currentPath);
Output: C:\projects\project2
Use the isAbsolute() method to check the input and then use the resolvePath if the isAbsolute() method returns false.
https://docs.oracle.com/javase/7/docs/api/java/nio/file/Path.html#isAbsolute()
The reason why you have to check if the path is absolute first is described below for the resolve method:
Path resolve(Path other)
Resolve the given path against this path. If the other parameter is an
absolute path then this method trivially returns other. If other is an
empty path then this method trivially returns this path. Otherwise
this method considers this path to be a directory and resolves the
given path against this path. In the simplest case, the given path
does not have a root component, in which case this method joins the
given path to this path and returns a resulting path that ends with
the given path. Where the given path has a root component then
resolution is highly implementation dependent and therefore
unspecified.
https://docs.oracle.com/javase/7/docs/api/java/nio/file/Path.html#resolve(java.nio.file.Path)

Why does Path class allow file within a file?

I'm playing around with the NIO Path stuff, and came across this quesion:
What will the following code fragment print?
Path p1 = Paths.get("\\personal\\readme.txt");
Path p2 = Paths.get("\\index.html");
Path p3 = p1.relativize(p2);
System.out.println(p3);
The answer is
..\..\index.html
But this would make the entire Path:
\personal\readme.txt\index.html
This looks like nonsense to me, as you can't put a file within a file like this. Can you?
If readme.txt were a directory instead of a file, I would be perfectly OK with this, but I'm very confused as to why it allows a filepath like this to exist?
Or is there some weird way that you can actually do this?
Both ISOs and Zip files (therefore JAR/WAR/XUL/CHM...) represent files that can contain a folder structure of files. These files can be handled either as a file, or as a folder; both are legitimate uses for them. Therefore, this would be semantically meaningful:
Path p1 = Paths.get("\\personal\\photos.zip");
Path p2 = Paths.get("\\family\\me.png");
Path p3 = p1.relativize(p2);
System.out.println(p3);"
While I am not aware of any implementations in Java that behave this way, it is a semantic used in XUL and Windows Explorer.
The result is ..\..\index.html
From the javadoc:
This method attempts to construct a relative path that when resolved
against this path, yields a path that locates the same file as the
given path. For example, on UNIX, if this path is "/a/b" and the given
path is "/a/b/c/d" then the resulting relative path would be "c/d".
Where this path and the given path do not have a root component, then
a relative path can be constructed.
This means that you would have to go up two folders from this path to reach a path from which you can reach your given path, index.html.
Remember, these are all paths, not actual files/file descriptors.
Path p1 = Paths.get("\\personal\\readme.txt");
Path p2 = Paths.get("\\personal\\index.html");
Path p3 = p1.relativize(p2);
System.out.println(p3);
prints ..\index.html, meaning from \\personal\\readme.txt, go up one and then access index.html.

getResourceAsStream fails under new environment?

Hallo,
i have following line of code:
InputStream passoloExportFileInputStream = getClass().getClassLoader().getResourceAsStream("/com/thinkplexx/lang/de/general.xml");
and i know that jar with com/thinkplexx/lang/de/general.xml is in classpath.
It worked under "previous environment", which is maven2 build.
Now, i evaluate maven3 and it doesn't work! I know, that if i change the code to be:
InputStream passoloExportFileInputStream = getClass().getClassLoader().getResourceAsStream("com/thinkplexx/lang/de/general.xml");
it works great (i just removed the first slash from the resource path).
Btw, i use Linux. First slash in path normally means "from the root directory", so if this logic is sound for java resource loading as well, first example should never have worked!?
Questions: is something wrong with the first code sample, i.e. with /com/ and not com/? Is it just bad code or it means something different?
thank you!
It depends on how you are getting the resource. When you use a ClassLoader as in:
InputStream stream= getClass().getClassLoader().getResourceAsStream("/com/thinkplexx/lang/de/general.xml");
The leading '/' is meaningless. So, the correct form is "com/thinkplexx/lang/de/general.xml".
If, instead you use a 'Class', as in:
InputStream stream= getClass().getResourceAsStream("/com/thinkplexx/lang/de/general.xml");
You get a different behavior. The Class.getResourceAsStream will consider classes without a leading '.' to be relative to the package containing the class. Resources specified with a leading '.' are absolute, or resolved relative to the root of the jar.
So, if this is a reference to com.example.SomeThing, then the expected behavior is:
getClass().getResourceAsStream("/a/b/c.xml") ==> a/b/c.xml
getClass().getResourceAsStream("a/b/c.xml") ==> com/example/a/b/c.xml
getClass().getClassLoader().getResourceAsStream("a/b/c.xml") ==> a/b/c.xml
getClass().getClassLoader().getResourceAsStream("/a/b/c.xml") ==> Incorrect
Maven2 was being lax and allowing the last form.

How do I rename (not move) a file in Java 7?

I'm a bit confused with all these new File I/O classes in JDK7.
Let's say, I have a Path and want to rename the file it represents. How do I specify the new name, when again a Path is expected?
Path p = /* path to /home/me/file123 */;
Path name = p.getName(); /* gives me file123 */
name.moveTo(/* what now? */); /* how to rename file123 to file456? */
NOTE: Why do I need JDK7? Handling of symbolic links!
Problem is: I have to do it with files whose names and locations are known at runtime. So, what I need, is a safe method (without exceptional side-effects) to create a new name-Path of some old name-Path.
Path newName(Path oldName, String newNameString){
/* magic */
}
In JDK7, Files.move() provides a short and concise syntax for renaming files:
Path newName(Path oldName, String newNameString) {
return Files.move(oldName, oldName.resolveSibling(newNameString));
}
First we're getting the Path to the new file name using Path.resolveSibling()
and the we use Files.move() to do the actual renaming.
You have a path string and you need to create a Path instance. You can do this with the getPath method or resolve. Here's one way:
Path dir = oldFile.getParent();
Path fn = oldFile.getFileSystem().getPath(newNameString);
Path target = (dir == null) ? fn : dir.resolve(fn);
oldFile.moveTo(target);
Note that it checks if parent is null (looks like your solution don't do that).
OK, after trying everything out, it seems I found the right method:
// my helper method
Path newName(Path oldFile, String newNameString){
// the magic is done by Path.resolve(...)
return oldFile.getParent().resolve(newNameString);
}
// so, renaming is done by:
oldPath.moveTo(newName(oldFile, "newName"));
If you take a look at Apache Commons IO there's a class called FileNameUtils. This does a ton of stuff wrt. file path names and will (amongst other things) reliably split up path names etc. I think that should get you a long way towards what you want.
If the destination path is identical to the source path except for the name of the file, it will be renamed rather than moved.
So for your example, the moveto path should be
/home/me/file456
If you can't get Java to do what you want with Unix I recommend Python scripts (run by your Java program). Python has get support for Unix scripting and it's not Perl :) This might sound inelegant to you but really in a larger program you'll benefit from using the right tool for the job.

Categories

Resources