How to get the short-filename for a long-filename in Windows using Java?
I need to determine the short-filenames of files, stored on a Windows system, using Java(tm).
-
I think this thread could be useful: stackoverflow.com/questions/1844688/read-all-files-in-a-folderErnestas Kardzys– Ernestas Kardzys2013年09月19日 11:37:40 +00:00Commented Sep 19, 2013 at 11:37
-
2This thread is useful as it highlights how to use JNA (Java(tm) Native Access) to access the Windows Win32 API function GetShortPathName() : stackoverflow.com/questions/11038595/…Osmund Francis– Osmund Francis2013年09月20日 18:51:35 +00:00Commented Sep 20, 2013 at 18:51
-
This thread details using command-line in the same way: stackoverflow.com/questions/10227144/…Osmund Francis– Osmund Francis2013年09月20日 19:01:32 +00:00Commented Sep 20, 2013 at 19:01
2 Answers 2
Self Answer
There are related questions with related answers. I post this solution, however, because it uses Java(tm) code without the need for external libraries. Additional solutions for different versions of Java and/or Microsoft(R) Windows(tm) are welcome.
Main Concept
Main concept lies in calling CMD from Java(tm) by means of the runtime class:
cmd /c for %I in ("[long file name]") do @echo %~fsI
Solution
Tested on Java SE 7 running on Windows 7 system (Code has been reduced for brevity).
public static String getMSDOSName(String fileName)
throws IOException, InterruptedException {
String path = getAbsolutePath(fileName);
// changed "+ fileName.toUpperCase() +" to "path"
Process process =
Runtime.getRuntime().exec(
"cmd /c for %I in (\"" + path + "\") do @echo %~fsI");
process.waitFor();
byte[] data = new byte[65536];
int size = process.getInputStream().read(data);
if (size <= 0)
return null;
return new String(data, 0, size).replaceAll("\\r\\n", "");
}
public static String getAbsolutePath(String fileName)
throws IOException {
File file = new File(fileName);
String path = file.getAbsolutePath();
if (file.exists() == false)
file = new File(path);
path = file.getCanonicalPath();
if (file.isDirectory() && (path.endsWith(File.separator) == false))
path += File.separator;
return path;
}
1 Comment
I found a slight problem Osmund's solution. It doesn't work properly for this file name for some reason:
N:\directoryY\tmp\temp\asdfasdf sdf dsfasdf [dfadss]\[asdfas] asdfasd asd asdfasdf ~fdfsdfdfdsfdfdfdfdfd~ TTTm7-9 [RR 1234a5678 A.888 OKOK]a
I'm not really sure why exactly. But if you run the command a slightly different way (using ProcessBuilder), it works. Here is the new code (I am using BufferedReader to read the output, it is much cleaner).
public static String getMSDOSName(String path) throws IOException, InterruptedException {
Process process = new ProcessBuilder().command("cmd", "/c", "for %I in (\"" + path + "\") do @echo %~fsI").start();
process.waitFor();
try (BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
return br.readLine();
}
}
This is the output of the original solution vs my solution. The original solution fails to shorten the last path element:
N:\DIRECT~1\tmp\temp\ASDFAS~1\[asdfas] asdfasd asd asdfasdf ~fdfsdfdfdsfdfdfdfdfd~ TTTm7-9 [RR 1234a5678 A.888 OKOK]a
N:\DIRECT~1\tmp\temp\ASDFAS~1\_ASDFA~1.888