Java two dots at the end of a path have unexpected results - java

I've run into what I thought was unusual behavior when working with some File objects.
import java.io.File;
public class MyClass
{
public static void main(String[] args)
{
File file = new File("C:\\x..");
System.out.println(file.isDirectory());
System.out.println(file.listFiles());
}
}
Assuming that some directory C:\x exists, file.isDirectory() will return true with the added two dots at the end of the path. This replicates the behavior in the command line, where cd x.. will change the directory to x.
However, when calling file.listFiles(), the method returns null, which is only supposed to happen if the file is not a directory. This seems to be inconsistent with the definition of the listFiles().
Why is this so? And why does having two dots at the end of the path go to the same directory as if there was no dots?
This problem seems to be exclusive to Windows. Linux correctly (?) returns false for isDirectory().

Windows trims trailing dots from path and filenames. I am unable to find a concrete reference for this, it's just one of those mysterious things that has always been that way.
It trims the trailing dots from the full pathname, not the individual components.
Therefore, while "C:\x...." is the same as "C:\x", "C:\x....\filename" is not the same as "C:\x\filename", as the latter does not have trailing dots.
You would have to look at the JDK's native FileSystem source on Windows to see precisely how it is obtaining a list of files, but I suspect it's doing some kind of search on e.g. "C:\x..\*.*" using Windows' FindFirstFile API call or something, where the dots are no longer trailing. In other words, presuming "C:\x" is a directory, while the path "C:\x.." is a directory, "C:\x..\*.*" matches nothing, and "C:\x..\subdirectory" does not map to "C:\x\subdirectory".
You should avoid using such paths. I'm not sure how you obtained that path string in the first place.
You can use File.getCanonicalPath() or File.getCanonicalFile() to convert it back to a more useable pathname.
By the way, if you want to have some fun with Windows, type the following in a command prompt (assuming "c:\windows\temp" exists, otherwise replace with some other path):
echo > \\?\c:\windows\temp\x.
The \\?\ prefix in Windows disables filename processing and expansion. Now delete the resulting file. Try it in Explorer too.
Spoiler:
You'll have to delete it with a wildcard from the console, e.g. del x?

You forgot to add extra slashes before .. to it should be c:\\x\\... This will point you to C: indeed

Related

Absolute path with string variable

PLEASE help me to understand what is going on here:
my code:
import java.io.File;
public class Main {
public static void main(String[] args) {
String name = "‪d:\\downloads\\testfile.mp3";
File file1 = new File(name);
System.out.println(file1.getAbsolutePath());
File file = new File("d:\\downloads\\testfile.mp3");
System.out.println(file.getAbsolutePath());
}
}
The output:
J:\Louw\Programming\PathTest\‪d:\downloads\testfile.mp3
d:\downloads\testfile.mp3
Question:
Why would the String variable produce a different Absolutepath than typing the string directly with new File object? (Obviously the first output also throws a "FileNotFound" exception if trying to use later).
my Eclipse java development environment is:
Eclipse Java EE IDE for Web Developers.
Version: Neon.2 Release (4.6.2)
Build id: 20161208-0600
Please assist.
Now I am not 100 % sure whether this is the correct explanation, but I believe it is consistent, so I also believe that it is worth for you to check.
When I copy your code into my Eclipse, your string name begins with a character with Unicode value 8234 (202A hexadecimal). This character is not printed, so the two strings look the same, but they are not. The mentioned character is not it the string that you pass when constructing the second File object. On fileformat.info the character is called “left-to-right embedding”, I don’t know what this means.
It would make sense that such a character in front of d:\\ would cause Java not to recognize the string as an absolute path name and therefore take it as a relative one, relative to your working directory.
It remains to be determined whether that character is in your source file too or only has crept in on Stack Overflow or in my copy-paste operation.
If the 8234 is indeed the culprit: in my Eclipse I can delete it with backspace as any other character, and everything works as expected. Failing that, you can always delete a sequence of characters containing at least the " before and the d after and type them again.
Where that char may come from, I have no good idea. It sounds unlikely that you should have typed Alt-202A on your keyboard without knowing you had done so.
Your code is fine, and is doing what you expect. It's printing ‪d:\downloads\testfile.mp3 twice.
Either something in how you execute your program is printing J:\Louw\Programming\PathTest\ with no newline to stdout before running your program, or you're seeing the system prompt and interpreting it as output.
You have a strange non-printable Unicode character at the start of your name String. The second instance of the string looks the same, but doesn't include that character. Paste the second string over the top of your first string and the problem will go away.

Regex to dynamically ignore some parts of a given path

Consider that I have the following string which is a "complete path":
/A/B/C/D/E
And there is also the "simplified path" string:
/A/B/E
I have a situation where some parts of the string can be omitted and still be represent the full path. I know this is strange, but I can't change it.
Basically for this case, I need a regex to ignore the last two paths before the current path (dynamically as I have no specific information of them), to confirm that these two strings have a correlation.
The only thing I could came up with was:
Take the current path (([^\/]+$)) from both strings and compare.
Check in Java if the complete string contains the simplified one.
But I think there must be a cleaner way to do this.
I came up with the following solution:
Search string:
[^\/]+\/[^\/]+\/([^\/]+$)
Replace string: \1
Check it here
If both path point to the same file/directory then you could make use of the Files class.
It has a method Files#isSameFile to which you pass two Path instances and it would check if both files are pointing to the same file at your directory. This simple line would check if A/B/E/ and /A/B/C/D/E are actually the same directory.
System.out.println(Files.isSameFile(Paths.get("/A/B/C/D/E"), Paths.get("/A/B/E")));

How to escape forward slash in java so that to use it in path

I am trying to escape forward slash in String which can be used in path using Java.
For example: String:: "Test/World"
Now I want to use above string path.At the same time I have to make sure that "Test/World" will come as it is in path. Sorry if its duplicate but I couldn't find any satisfactory solution for this.
My purpose is to use above string to create nodes in Zookeeper.
Example:
If I use following string to create node in Zokkeeper then I should get "Test/World" as a single node not separate. Zookeeper accepts "/" as path separator which in some cases I dont require.
/zookeeper/HellowWorld/Test/World
Thanks
You should know about File.separator ... This is safer than \ or / because Linux and Windows use different file separators. Using File.separator will make your program run regardless of the platform it is being run on, after all, that is the point of the JVM. -- forward slash will work, however, File.separator will make you end users more confident that it will.
And you don't need to escape "/ ... you should also see the answer to this question
String fileP = "Test" + File.separator + "World";
In order to escape a character in Java use "\"
for example:
String strPath = "directory\\file.txt".
I believe you do not need to escape forward slashes such as: "/"
Let me rephrase your question. You are trying to create a node in zookeeper and it should be /zookeeper/HelloWorld/NodeName. But the last part "NodeName" is actually "Test/World", and you are looking for ways to escape "/" so the node name can be "Test/World".
I don't think it would work escaping the char, unless you tried with unicode.
Try \u002F which is the equivalent for /.
We are trying to solve exactly the same problem (using filesystem path as node name in zookeeper) a we haven't found a way how to have '/' in node name.
Solution would be either to replace '/' with some character, that cannot appear in your node name. For paths that would be '/' or '\0', which wont help us in this case.
Other possibility is to replace '/' with string of characters allowed in node name, e.g. "Test/World" -> "Test%#World", "Test%World" -> "Test%%World" and add escaping/de-escaping to saving and loading.
If there is any more straightforward way, I'd love to hear it.
I don't know anything about Zookeeper. But it looks to me as though you're trying to keep a list of strings like "zookeeper", "HellowWorld", "Test/World", that you then want to use either to create Zookeeper nodes or to create a pathname in a file system. (I'm assuming that if you're working with a file system, you're going to have a subdirectory Test and a file or subdirectory World in the Test subdirectory. If you're actually trying to create a single file or directory named Test/World, give up. Both Linux and Windows will fight with you.)
If that's the case, then don't try to represent the "path" as a simple String that you pass around in your program. Instead, represent it as a String[] or ArrayList<String>, and then convert it to a filesystem path name only when you need a filesystem path name. Or, better, define your own class with a getFilesystemPath method. Converting your list of node names to a pathname String too early, and then trying to reconstruct the list from the String later, is a poor approach because you throw away data that you need later (in particular, you're throwing away information about which / characters are separators and which ones are part of node names).
EDIT: If you also need a single path name for Zookeeper, as you mentioned in another comment, I can't help you since I don't know Zookeeper and haven't found anything in a quick look at the docs. If there is a way to escape the slash for Zookeeper, then I still recommend defining your own class, with a getFilesystemPath method and a getZookeeperPath method, since the two methods will probably return different Strings in certain cases. The class would internally keep the names as an array or ArrayList.

Java on Windows: prevent '/' slash in file name from acting as a separator

I have to create a file based on a string provided to me.
For this example, let's say the file name is "My file w/ stuff.txt".
When Java creates the file using
File file = new File("My file w/ stuff.txt")
Even though the default windows separator is '\', it assumes that the '/' slash is a file separator. So a future call to file.getName() would return " stuff.txt". This causes problems for my program.
Is there any way to prevent this behaviour?
According to this Wikipedia page, the Windows APIs treat / as equivalent to \. Even if you somehow managed to embed a / in a pathname component in (for example) a File object, the chances are that Windows at some point will treat it as a path separator.
So your options are:
Let Windows treat the / as it would normally; i.e. let it treat the character as a pathname separator. (Users should know this. It is a "computer literacy" thing ... for Windows users.)
As above, but with a warning to the user about the /.
Check for / AND \ characters, and reject both saying that a filename (i.e. a pathname component) cannot contain pathname separators.
Use some encoding scheme to encode reserved characters before attempting to create the files. You must also then apply the (reverse) decoding scheme at all points where you need to show the user their "file name with slashes".
Note: if the user can see the actual file paths (e.g. via a command shell) you can't hide the encoding / decoding from them. Arguably, that is worse than the "problem" you were trying to solve in the first place.
There is no escaping scheme that the Windows OS will accept for this purpose. You would need to use something like % encoding; e.g. replace / with %2F. Basically you need to "hide" the slash character from Windows by replacing it with other characters in the OS-level pathname!
The best option depends on details of your application; e.g. whether you can report problems to the person who entered the bogus filename.
If a string is being provided to you (from an external source), it doesn't sound like you can prevent that string from containing certain characters. If you have some sort of GUI to create the string, then you can always restrict it there. Otherwise, whatever method is creating your file should check for a slash and either return an error or handle it as you see fit.
Since neither forward nor backward slashes are allowed in windows file names, they should be cleaned out of the Strings used to name files.
Well, how could you stop it being a folder separator? It is a folder separator. If you could just decide for yourself what was and what wasn't a folder separator, then the whole system would come crashing down.

Error when using Runtime.getRuntime().exec method to invoke an exe, if exe path has non-english chars

I am using Runtime.getRuntime.exec() Method to invoke an exe. The problem what I face with this method is that when I pass some exe path (c:\JPN_char_folder\mypath\myexe.exe) with other language chars (ex.Japanese) "it's saying "System cannot find the file specified". Would you please suggest some ideas to get around this? I even tried passing that exe path after converting to UTF-8 as well, but still I could not solve this.
-Robert.
I don't think that Japanese characters are the issue; it's the c: drive.
You need to write it this way:
String path = "c:\\\JPN_char_folder\\mypath\\myexe.exe";
See if that helps.
Most probably you have an encoding problem somewhere.
There are several steps here that the path value takes:
InstallAnywhere retrieves the path
InstallAnywhere puts it into a variable
Java reads the variable
Java puts it into a String
Java creates a java.io.File instance from String
Java runtime passes path (via File) to OS
Somehwere along this sequence something goes wrong with the path :-(.
It's hard to tell where; your best bet probably is to try and print out the value at every step along the path, to see where it goes wrong.
At least from inside Java, you should probably print out the String both as text, and as a list of Unicode code points (using String.codePointAt). That way you can see the real data Java uses.
Another approach:
Print out the value Java gets from InstallAnywhere (as text & as codepoints, as above)
Try to put the path into your Java program as a String literal, and fiddle until you can open the file that way. Then print that String as well.
Now you can compare the two results; that should give you an idea where the path gets messed up.
Note:
Does the path contain characters outside the Basic Multilingual Plane (BMP)? Java handles these a bit awkwardly, so you need to pay extra attention. Maybe you can check this first.
Even if you're using Windows, you can use slashes when specifying directories. This will help you with escaping backslash hell.
For example, on my system, 7z is located in directory c:\Program Files\7-Zip\.
Executing this
File file = new File("c:/Program Files/7-Zip/7z.exe");
if(file.exists()) {
System.out.println(file.getAbsolutePath());
}
Results in
c:\Program Files\7-Zip\7z.exe
being printed on the console.
I'd suggest you try using this idiom, i.e. check if .exe file exits before trying to execute it.

Categories