Java Paths.get() strange behavior on Linux - java

I am currently writing some code in which I work with files a lot. I implemented all file paths processing (concatenation, normalization, etc) using the Java 7 nio classes Paths and Path. On Windows everything works as expected however on Linux the Paths class behavior seems to be broken.
For example the following code:
System.out.println(File.separator);
System.out.println(FileSystems.getDefault());
Path path = Paths.get("../dir1/", "\\dir2\\file1").toAbsolutePath().normalize();
System.out.println(path);
if(path.toFile().exists()) {
System.out.println(path + " exists");
}
on Windows prints the following output:
\
sun.nio.fs.WindowsFileSystem
D:\projects\dir1\dir2\file1
true
but the same code on Linux Ubuntu 14.04 on both Java 1.7.0_79 (64 bit) and Java 1.8.0_60 (64 bit) leaves the path un-normalized:
/
sun.nio.fs.LinuxFileSystem
/home/semi/dir1/\dir2\file1
Also even if the file is at path /home/semi/dir1/dir2/file1 exists it is reported as non-existent by path.toFile().exists().
I looked a bit over LinuxFileSystem.java and WindowsFileSystem.java and it seems that on windows the path is checked for both / and \ characters (in WindowsPathParser.isSlash(char c) method). Shouldn't the Linux implementation do the same?
Is this a bug in sun.nio.fs.LinuxFileSystem implementation or am I doing something wrong?
Also do you know any alternative to make sure Linux paths are parsed and normalized correctly (without doing all the parsing manually).

In Windows, / is not a valid character in a filename so any code can assume it's a wrongly typed path separator.
In Linux, just about any byte is acceptable in a filename. In your Paths.get(), you're effectively joining a path called dir1 (1 level deep) and a path called \dir2\file1 (also 1 level deep).

Java on Windows is compiled against Microsoft C++ standard libraries, which permit either backslash or forward slash as a valid path separator. So backslash is a valid path separator only when running on Windows, whereas forward slash is valid everywhere.
The only time backslash is required, even on Windows, is when creating command lines that will be passed to CMD.EXE, to PowerShell, and possibly other terminals/shells. There are also some open source libraries that require backslash in file paths (when running on Windows), but java itself permits either forward or back slash in file paths.
IMHO, using File.separator when parsing input often leads to avoidable errors, whereas it has a valid role when generating output to be consumed by software or human eyeballs.

Related

Calling Java from command line - Linux vs Windows

On Windows I run the following command and it work;
java -cp "./libs/*;" SampleJavaApp
When I try to run the same command on Linux (CentOS 6) I get
Error: Could not find or load main class SampleJavaApp
SampleJavaApp has no package
Any insight as to why would be appreciated.
Thanks
UPDATE
The Java Version was the problem, as well as the :
The format of the classpath (-cp argument) uses the operating system path separator, to match the behavior of PATH. So you want : instead of ; for separating paths.
Also, you seem to be using an empty path element when I think you want to explicitly reference the current directory ..
Also, I think the handling of the * wildcard varies by Java implementation, so you need to make sure the versions match.

Windows couldn't remove file with large path

Google Web Toolkit (GWT) generates huge number of temporary files in the temp (C:\Users\User01\AppData\Local\Temp) directory.
Example of a file path:
C:\Users\User01\AppData\Local\Temp\gwt-codeserver-1101830889369654349.tmp\com.company01.web.builder.BuildingsWeb\compile-2\gen\com\company01\web\theme\custom_pluto123\client\base\progressbar\Css3ProgressBarAppearance_Css3ProgressBarTemplate_render_SafeHtml__SafeHtml_text__Css3ProgressBarStyles_style__SafeStyles_wrapStyles__SafeStyles_progressBarStyles__SafeStyles_progressTextStyles__SafeStyles_widthStyles___SafeHtmlTemplatesImpl.java
The above file path contains 437 characters.
When I tried to remove this type of files from Windows Explorer, it got crashed. Also I've tried to remove or rename it from command prompt it says The filename or extension is too long.
Finally I deleted by running custom java program.
Now, my question is why Windows couldn't able to remove it? If its not supported by OS, how java removes it?
Note:
I tried all of the above commands/actions with proper UAC (Run as administrator) in Windows 7 Ultimate and the File System was NTFS
Windows had an limitation of 260 characters (=MAX_PATH) but now also allows to create paths with up to 32,767 characters through the Unicode version of its API.
Windows Explorer sadly cannot handle long paths.
Java seems to use the Unicode API and therefore can create and remove long paths.
Resources:
https://support.microsoft.com/en-us/kb/320081
https://msdn.microsoft.com/en-us/library/aa365247%28VS.85%29.aspx

java.nio.file.path: inconsistent behaviour with name count?

While learning about the behaviour of the NIO2 API I have considered this:
Path unix = Paths.get("/");
Path windows = Paths.get("c:\\");
System.out.println(unix.getNameCount());
System.out.println(windows.getNameCount());
... gives the output
0
1
Why is that? I would expect the same result which should actually be 0 because there is no name but only a root. When I add a folder
Path unix = Paths.get("/etc");
Path windows = Paths.get("c:\\etc");
System.out.println(unix.getNameCount());
System.out.println(windows.getNameCount());
... then I get
1
1
Isn't that confusing for the Windows part?
Edit: I'm on a linux machine myself.
Alright, now I found the right explanation:
A Path instance reflects the underlying platform. In the Solaris OS, a Path uses the Solaris syntax (/home/joe/foo) and in Microsoft Windows, a Path uses the Windows syntax (C:\home\joe\foo). A Path is not system independent.
From here: http://docs.oracle.com/javase/tutorial/essential/io/pathClass.html
That means in my case on a linux machine the path "c:\\\\" would be the name of a relative folder within my working directory.

Raspbian/Java: Classpath and MySQL, working in Windows and not on Pi

I know this question has been asked/answered several times, but I still couldn't find a solution to this ClassNotFoundException error, because it works on my computer but not on my RasPi (on which I installed OpenJDK7).
My application uses JDBC to access a MySQL database, and that's the main problem. As has been pointed out on lots of websites ([1], [2], [3]), this is, unfortunately, a common problem.
So, I'm using the mysql-connector-java-5.0.8.jar as a driver. My folder structure is something like /src/de/web/project/ I'm calling the main method via java de.web.project.WakeOnLan (which is the main class that starts all other classes etc.) I got the common ClassNotFound exception and therefor added the -cp parameter so I called the project via java -cp .;mysql-connector-java-5.0.8.jar de.web.project.WakeOnLan to add the driver to classpath.
This worked nicely on my Windows computer from command line, but now I want to push this code to my Raspberry Pi and execute it there. As I said, I installed OpenJDK7 there (using apt-get, if this should be important), used SFTP to upload the folder structure and the code to /home/pi/java/ where there is also the ejre1.7.0_10 folder (so the code is now actually in /home/pi/java/de/web/project/).
I now went back to /home/pi/java and entered java -cp .;mysql-connector-java-5.0.8.jar de.web.project.WakeOnLan as I did on my Windows computer, but it refuses to work (I've put the connector in any folder on the way, just in case). When I call this function, I get a long list of hints Java wants to give me which parameters are allowed for java, finally stating: -bash: mysql-connector-java-5.0.8.jar: command not found. I also tried to turn ".;mysql..." around to "mysql...;." which didn't work as well. If I don't include the -cp parameter, my program says "Thread started" and in the next line: java.lang.ClassNotFoundException: com.mysql.jdbc.Driver etc., so the program does indeed start and writes "Thread started" to System.out.
For some reason, it looks like Java on the Pi ignored the second value of the classpath parameter for which I don't see a good reason.
You might just have problem in classpath setting, there is difference for windows and linux
The classpath syntax is OS-dependent. From Wikipedia :
Being closely associated with the file system, the command-line
Classpath syntax depends on the operating system. For example:
on all Unix-like operating systems (such as Linux and Mac OS X), the
directory structure has a Unix syntax, with separate file paths
separated by a colon (":").
on Windows, the directory structure has a Windows syntax, and each
file path must be separated by a semicolon (";").
This does not apply when the Classpath is defined in manifest files,
where each file path must be separated by a space (" "), regardless of
the operating system.

Imagemagick not working in windows + java

I am using imagemagick in my application. Our development machine is Windows and live server is linux. Now, in online it is working fine online. But not in development machine. I downloaded and installed Imagemagick latest release for Windows and when i try the below command in DOS-prompt, it is working fine.
convert -sample 100x100 D:\test.jpg D:\test-cropped.jpg
But when i run the same as command-line in Java program, it is not working and not giving any error too.
My code is :
Runtime.getRuntime().exec("convert -sample 250x150 "+pathName+digest+".jpg "+pathName+digest+"_thumb.jpg");
Any help is appareciated.
convert.exe is available in ImageMagick installation directory. So you need to add ImageMagick installation directory in environment variable path.
Another option is to provide complete path of convert.exe as :
Runtime.getRuntime().exec("C:\\program files\\ImageMagick\\convert -sample 250x150 "+pathName+digest+".jpg "+pathName+digest+"_thumb.jpg");
try
execute convert using the absolute path
quote your parameter input file and output file, in case they contain space
I suspect the problem is spaces in pathnames, but the solution is NOT to use escapes or quotes. The exec(String) method splits the string into "arguments" in a completely naive fashion by looking for white-space. It pays no attention whatsoever to quoting, etcetera. Instead, you will end up with command names and arguments that have quote characters, etcetera embedded in them.
The solution is to use the overload of exec that takes a String[], and do the argument splitting yourself; e.g.
Runtime.getRuntime().exec(new String[]{
"convert", // or "D:\\Program Files (x86)\\ImageMagick-6.8.0-Q16\\convert\\"
"-sample",
"250x150",
pathName + digest + ".jpg",
pathName + digest + "_thumb.jpg"
});
The other thing you could do is to capture and print any output that is written to the processes stdout and stderr.
In my case, the problem I was facing that from java compare command was working fine using Runtime.getRuntime().exec(), but when using convert, it was not working and returning me exit value as 4.
Compare execution returns exit value 0, telling that it is successfully executed.
I have system path updated with the ImageMagic's installation directory, still it was not picking 'convert' exe file. So, I started giving complete path of the convert.exe file instead of only writing only convert
e.g:
Runtime.getRuntime().exec("C:/Program files/ImageMagic......../convert.exe myImage1 -draw .... myImage2") and it worked fine this time.
Some how system was not able to pick the convert application and giving full path sorted it out. May be this solution would help someone facing same type of issue.

Categories

Resources