Relativise introducing redundant up-directory ".." - java

I'm copy files from a jar to a local folder.
The jar is located at a/b.
The folder (in the jar) I'm trying to extract is located at b/c
The destination folder should be z, i.e. a/b/c/x -> z/x
When I use c.relativize("x") I get ../c/x instead of x.
This is a problem when I then try to do: z.resolve(c.relativize(x)).
I get z/../c/x instead of z/x
How do I fix this issue?
I tried z.resolve(c.relativize(x).normalise()) but get the same result
The jar is b in the folder a. c is a resource (folder) inside the jar b. x is a file inside the folder c.

The jar is in folder A/B/
The source folder path inside the jar is /b/c/ with file /b/c/xxx.yyy
The destination folder is Z
The destination file should have path: Z/xxx.yyy
So:
Path sourceZip = Paths.get("/A/B/my.zip");
URI sourceZipURI = URI.create("jar:" + sourceZip.toUri());
Path targetFolder = Paths.get("/Z");
Map<String, Object> senv = new HashMap<>();
try (FileSystem sourceZipFS = FileSystems.newFileSystem(sourceZipURI, senv, null)) {
Path folderInZip = sourceZipFS.getPath("/b/c");
Files.list(folderInZip).forEach(p -> {
Path target = targetFolder.resolve(folderInZip.relativize(p).toString());
try {
Files.createDirectories(target.getParent());
Files.copy(p, target);
} catch (IOException e) {
e.printStackTrace();
}
});
}
The main issue was the reversal of relativize; not the first time I encountered the misunderstanding. child.relativize(parent) gives a .. whereas parent.relativize(child) truncates the path.
To get the target path one needs to convert the source Path to a string, to prevent combining two different file systems.
(I did not take care of subdirectories.)

I think you have misunderstood the usage of path.relativize(Path)
According to https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/file/Path.html#relativize(java.nio.file.Path), there is a statement as below:
Constructs a relative path between this path and a given path.
e.g.
Path pathA = Paths.get("a"); // i.e. /a or /anyDir/anySubDir/a
Path pathB = Paths.get("b"); // i.e. /b or /anyDir/anySubDir/b
pathA.relativize(pathB)
Assume the result is ../b, what does it mean?
It is actually telling you: as you are inside directory a, if you want to access directory b, you need to access by this approach cd ../b.
relativize(Path) is helping to analyzing the relative path between the parent Path and the child Path (i.e. how to access from parent Path to child Path).
Alternatively, from your question, looks like you are preferring to "construct" the path instead of "analyzing" the relative path. relativize(Path) is not the one for this purpose.
So, which one, "construct" manually or "analyze", do you want to achieve?

Related

How to get the path of the file from source root in java?

I have a file in java under the src folder, I want to get its path at runtime relative to the source folder.
For example-
myProject
-- src
-- packageOne
-- SomeFile.java
I would like to have the result packageOne/SomeFile.java. I couldn't find a way, I tried getPath(), getAbsoultePath() and every similar method.
You want to construct a relative path. AFAIK there is no ready function to use.
Given that you have one of the ancestor nodes (src) and you have SomeFile.java, the following code might work but I did not try...
File src = new File("...");
File somefile = new File("...");
String relpath = somefile.getName();
File cursor = somefile.getParentFile();
while (!cursor.getAbsolutePath().equals(src.getAbsolutePath()) {
somefile = cursor.getName() + File.pathSeparator + somefile;
}
System.out.println("relative path: "+relpath);

Getting an element inside a directory using java.nio.file.Path's

I am currently getting to grips with file management in Java. As far as i've read, java.nio.file.Path is the preferred way of doing so.
Say I want to copy the contents of oldDir to the, currently empty, newDir. Every time I copy a file, I need this loong line just to get the Path of newFile:
Path newDir = FileSystems.getDefault().getPath("new");
Path oldDir = FileSystems.getDefault().getPath("old");
for (Path oldFile : oldDir) {
Path newFile = FileSystems.getDefault().getPath("new", oldFile.getFileName().toString()); // Why so complicated? :(
Files.copy(oldFile, newFile);
}
Is there something like newDir.getChild(oldFile.getFileName()) to do what I want, or is there really no shorter way of doing it?
There are a couple things you can do to make the code simpler:
Use Path#of(String,String...) or Paths#get(String,String...) to create your Path instances. Both methods delegate to the default FileSystem. The former was added in Java 11 and is now the preferred approach.
Use Path#resolve(Path) to append a relative path to some absolute path.
But there's also an error in your code. You are iterating over oldDir which works because Path implements Iterable<Path>. However, that iterates over the names of the path, not the children of the path. In other words, this:
Path path = Path.of("foo", "bar", "file.txt");
for (Path name : path) {
System.out.println(name);
}
Will output:
foo
bar
file.txt
If you want to iterate over the children of a directory you need to use something like Files#list(Path) or Files#newDirectoryStream(Path) (the latter has two overloads). Both those methods only return the immediate children of the directory. There are other methods available to recursively iterate a directory and its sub-directories; browse the Files documentation to see what's provided.
So your code should instead look something like:
Path oldDir = Path.of(...);
Path newDir = Path.of(...);
try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(oldDir)) {
for (Path oldFile : dirStream) {
Path newFile = newDir.resolve(oldFile.getFileName());
Files.copy(oldFile, newFile);
}
}

Java - How to get the correct absolute path of a file within a project

I have an XML file in a folder within my Java project, and I'd like to get its absolute path, so I can load it as a File in order to parse it(DOM). Instead of using an absolute/relative path, I want to specify only the file name, and get the absolute path after that. I tried to do this in a few different ways, but there is always a folder name missing from the path I get.
I get:
C:\Users\user\workspace\projectName\Input.xml<br>
instead of:
C:\Users\user\workspace\projectName\\**Folder1**\\Input.xml
-
File input = new File(project.getFile("Input.xml").getLocation().toString());`
File input = new File(project.getFile("Input.xml").getRawLocation().makeAbsolute().toString());
File input = new File(project.getFile("Input.xml").getLocationURI().getRawPath().toString());
File input = new File(project.getFile("Input.xml").getFullPath().toFile().getAbsolutePath());
How can I get the correct path, that includes that Folder1?
Reading your question (your project are in workspace directory) I suppose you're talking of a project in Eclipse.
Well the default directory where your app run into Eclipse is right the base dir of your project.
So if you run something like this in your main:
Files.newDirectoryStream(Paths.get("."))
.forEach(path -> {
System.out.println(path);
System.out.println(path.toFile().getAbsolutePath());
});
You should see all the files and directory that are in your project.
So if what you want is just the absolute path to your project run:
System.out.println(Paths.get(".").toFile().getAbsolutePath());
If you want open the resource Input.xml specifying only the name, I suggest to move all the files you need in a directory and run a method like this:
public static File getFileByName(String name, String path) throws IOException {
ArrayList<File> files = new ArrayList<>();
Files.newDirectoryStream(Paths.get(path))
.forEach(p -> {
if (p.getFileName()
.equals(name))
files.add(p.toFile());
});
return files.size() > 0 ? files.get(0) : null;
}

Get directory from classpath (getting a file now)

I want to search for files in a directory. Therefore I want to get the directory in a File object but i'm getting a file instead of a directory. This is what I'm doing, it prints false but I want it to be true.
URL url = getClass().getResource("/strategy/viewconfigurations/");
File folder = new File(url.toString());
System.out.println(folder.isDirectory());
How can I load this way a directory?
It seems path or String you will got from the URL object cause problem.
You passed file path which you will got from the url.toString().
You need to change below line
File folder = new File(url.toString());
with this line
File folder = new File(url.getPath());
You need path of that folder which will you get from URL.getPath() function.
I hope this is what you need.
If you need an alternative for Java 7+ to Yagnesh Agola's post for finding a directory from a classpath folder, you could you also the newer java.nio.file.Path class.
Here is an example:
URL outputXml = Thread.currentThread().getContextClassLoader().getResource("outputXml");
if(outputXml == null) {
throw new RuntimeException("Cannot find path in classpath");
}
Path path = Paths.get(outputXml.toURI());

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.

Categories

Resources