I'm working with IBM OmniFind, with has a fun way of handling file paths. If you've got a path like this:
C:\temp\some §$% path\temp - Sho rtcut.lnk
It becomes to this sort of "URI" (that's what they call it...):
file:///C:/temp/some+%C2%A7%24%25+path/temp+-+Sho+rtcut.lnk
This clearly seems to be escaped with URLEncoder.encode. Normally, Java would build this sort of URI from the path above:
file:/C:/temp/some%20%C2%A7$%25%20path/temp%20-%20Sho%20rtcut.lnk
file:/C:/temp/some%20§$%25%20path/temp%20-%20Sho%20rtcut.lnk
Now I have a really hard time of transforming this sort of URL Encoded Path into something that would work for File handles. This sort of does the trick, although it seems like a very questionable workaround:
String path = "file:///C:/temp/some+%C2%A7%24%25+path/temp+-+Sho+rtcut.lnk";
URL url = new URL(path);
path = url.toExternalForm().replaceAll("[+]", "%20");
URI uri = new URI(path);
File file = new File(uri);
System.out.println(file.exists());
Is there any safe-ish way of transforming URL escaped file paths to valid URIs in Java?
Related
I can request the URL for the jar file or classes directory where Java loaded a class from:
Class clazz = ...
URL url = clazz.getProtectionDomain().getCodeSource().getLocation();
but how to correctly convert this to a File (or Path) - especially with respect to some characters of the path escaped in URLs? I've tried this:
String fileName = URLDecoder.decode(url.getFile(), "UTF-8");
File jarFileOrClassesDir = new File(fileName);
but this causes problems if there is a + inside the path (the + is replaced with a space).
but this causes problems if there is a + inside the path (the + is replaced with a space).
This is standar behavior of URLDecoder. See more information at JavaDoc [1], plus (+) is mentioned there as well.
Solution using Paths
Using Paths#get(URI) [2] should preserve all "special" symbols and you can pass directly URI which can be retrieved directly from URL using URL#toURI() [3].
So in summary:
final var filePath = Paths.get(url.toURI()); // We can extract any information from Path e.g. fileName.
shoud work as expected.
[1] https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/net/URLDecoder.html
[2] https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/file/Paths.html#get(java.net.URI)
[3] https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/net/URL.html#toURI()
I'm trying to get this folder
File imagesOrg = new File(getClass().getResource("/stock").getPath());
I've printed it out in console with
System.out.println(imagesOrg.getAbsolutePath());
and there is a space within my path so it was changed to %20 and because of that the rest of my code doesn't work which is:
for(final File child : imagesOrg.listFiles()) {
System.out.println(child.getName());
}
If I put the whole path in new File with a space instead of %20 it works fine is there an easy solution to this?
I recommand URL decoder.
You can use like this..
String result = java.net.URLDecoder.decode(url, "UTF-8");
I'm having trouble coverting from a URI to a nio.Path in the general case. Given a URI with multiple schemas, I wish to create a single nio.Path instance to reflect this URI.
//setup
String jarEmbeddedFilePathString = "jar:file:/C:/Program%20Files%20(x86)/OurSoftware/OurJar_x86_1.0.68.220.jar!/com/our_company/javaFXViewCode.fxml";
URI uri = URI.create(jarEmbeddedFilePathString);
//act
Path nioPath = Paths.get(uri);
//assert --any of these are acceptable
assertThat(nioPath).isEqualTo("C:/Program Files (x86)/OurSoftware/OurJar_x86_1.0.68.220.jar/com/our_company/javaFXViewCode.fxml");
//--or assertThat(nioPath).isEqualTo("/com/our_company/javaFXViewCode.fxml");
//--or assertThat(nioPath).isEqualTo("OurJar_x86_1.0.68.220.jar!/com/our_company/javaFXViewCode.fxml")
//or pretty well any other interpretation of jar'd-uri-to-path any reasonable person would have.
This code currently throws FileSystemNotFoundException on the Paths.get() call.
The actual reason for this conversion is to ask the resulting path about things regarding its package location and file name --so in other words, as long as the resulting path object preserves the ...com/our_company/javaFXViewCode.fxml portion, then its still very convenient for us to use the NIO Path object.
Most of this information is actually used for debugging, so it would not be impossible for me to retrofit our code to avoid use of Paths in this particular instance and instead use URI's or simply strings, but that would involve a bunch of retooling for methods already conveniently provided by the nio.Path object.
I've started digging into the file system provider API and have been confronted with more complexity than I wish to deal with for such a small thing. Is there a simple way to convert from a class-loader provided URI to a path object corresponding to OS-understandable traversal in the case of the URI pointing to a non-jar file, and not-OS-understandable-but-still-useful traversal in the case where the path would point to a resource inside a jar (or for that matter a zip or tarball)?
Thanks for any help
A Java Path belongs to a FileSystem. A file system is implemented by a FileSystemProvider.
Java comes with two file system providers: One for the operating system (e.g. WindowsFileSystemProvider), and one for zip files (ZipFileSystemProvider). These are internal and should not be accessed directly.
To get a Path to a file inside a Jar file, you need to get (create) a FileSystem for the content of the Jar file. You can then get a Path to a file in that file system.
First, you'll need to parse the Jar URL, which is best done using the JarURLConnection:
URL jarEntryURL = new URL("jar:file:/C:/Program%20Files%20(x86)/OurSoftware/OurJar_x86_1.0.68.220.jar!/com/our_company/javaFXViewCode.fxml");
JarURLConnection jarEntryConn = (JarURLConnection) jarEntryURL.openConnection();
URL jarFileURL = jarEntryConn.getJarFileURL(); // file:/C:/Program%20Files%20(x86)/OurSoftware/OurJar_x86_1.0.68.220.jar
String entryName = jarEntryConn.getEntryName(); // com/our_company/javaFXViewCode.fxml
Once you have those, you can create a FileSystem and get a Path to the jar'd file. Remember that FileSystem is an open resource and needs to be closed when you are done with it:
try (FileSystem jarFileSystem = FileSystems.newFileSystem(jarPath, null)) {
Path entryPath = jarFileSystem.getPath(entryName);
System.out.println("entryPath: " + entryPath); // com/our_company/javaFXViewCode.fxml
System.out.println("parent: " + entryPath.getParent()); // com/our_company
}
I have get this exception. but this exception is not reproduced again. I want to get the cause of this
Exception Caught while Checking tag in XMLjava.net.URISyntaxException:
Illegal character in opaque part at index 2:
C:\Documents and Settings\All Users\.SF\config\sd.xml
stacktrace net.sf.saxon.trans.XPathException.
Why this exception occured. How to deal with so it will not reproduce.
A valid URI does not contain backslashes, and if it contains a : then the characters before the first : must be a "protocol".
Basically "C:\Documents and Settings\All Users\.SF\config\sd.xml" is a pathname, and not a valid URI.
If you want to turn a pathname into a "file:" URI, then do the following:
File f = new File("C:\Documents and Settings\All Users\.SF\config\sd.xml");
URI u = f.toURI();
This is the simplest, and most reliable and portable way to turn a pathname into a valid URI in Java. It should work on Windows, Mac, Linux and any other platform that supports Java. (Other solutions that involve using string bashing on a pathname are not portable.)
But you need to realize that "file:" URIs have a number of caveats, as described in the javadocs for the File.toURI() method. For example, a "file:" URI created on one machine usually denotes a different resource (or no resource at all) on another machine.
The root cause for this is file path contains the forward slashes instead of backward slashes in windows.
Try like this to resolve the problem:
"file:" + string.replace("\\", "/");
You must have the string like so:
String windowsPath = file:/C:/Users/sizu/myFile.txt;
URI uri = new URI(windowsPath);
File file = new File(uri);
Usually, people do something like this:
String windowsPath = file:C:/Users/sizu/myFile.txt;
URI uri = new URI(windowsPath);
File file = new File(uri);
or something like this:
String windowsPath = file:C:\Users\sizu\myFile.txt;
URI uri = new URI(windowsPath);
File file = new File(uri);
It needs a complete uri with type/protocol
e.g
file:/C:/Users/Sumit/Desktop/s%20folder/SAMPLETEXT.txt
File file = new File("C:/Users/Sumit/Desktop/s folder/SAMPLETEXT.txt");
file.toURI();//This will return the same string for you.
I will rather use direct string to avoid creating extra file object.
I had the same "opaque" error while passing a URI on the command line to a script. This was on windows. I had to use forward slashes, NOT backslashes. This resolved it for me.
it doesn't like spaces as well and it has to be / instead of \ or `\ or //
zipFilePath = "C:/test/v";
I've this brief snippet:
String target = baseFolder.toString() + entryName;
target = target.substring(0, target.length() - 1);
File targetdir = new File(target);
if (!targetdir.mkdirs()) {
throw new Exception("Errore nell'estrazione del file zip");
}
doesn't mattere if I leave the last char (that is usually a slash). It's done this way to work on both unix and windows. The path is actually obtained from the URI of the base folder. As you can see from baseFolder.toString() (baseFolder is of type URI and is correct). The base folder actually exists. I can't debug this because all I get is true or false from mkdir, no other explanations.The weird thing is that baseFolder is created as well with mkdir and in that case it works.
Now I'm under windows.
the value of target just before the creation of targetdir is "file:/C:/Users/dario/jCommesse/jCommesseDB"
if I cut and paste it (without the last entry) in windows explore it works...
The path you provide is not a file path, but a URI.
I suggest you try the following :
URI uri = new URI("file://c:/foo/bar");
File f = new File(uri).
It looks, to me, as if the "file:/" at the beginning is the problem... Try getAbsolutePath() instead of toString().
The File constructor taking a String expects a path name. A path name is not an URI.
Remove the file:/ from the front of the String (or better yet, use getPath() instead of toString()) to get to the path you need.