In some rare occasions you might want to find out the short filename of a file in Windows (for example to run legacy code). After looking around on the net, I couldn't find a java function to do it. And no, messing around with the output of dir /x is not a pretty solution.
Microsoft provides a Windows API function called GetShortPathName, which you can call from java using JNI. Too lazy actually messing around with JNI I found a package called NativeCall which allows calling a Windows API function from java without using JNI.
Here's the code for retrieving the short (8.3) filename given a long filename. Have fun with it. Don't forget to download the nativecall package and to add it to your classpath. For the lazy people I've made a zip containing this class, the two jars and how to execute it.
import com.eaio.nativecall.*;
public class EightPointThree {
public static void main(String[] args) {
String usage = "java " + EightPointThree.class.getName()
+ " longfilename";
if (args.length != 1) {
System.err.println(usage);
System.exit(1);
} else {
System.out.println(getEightPointThree(args[0]));
}
}
/**
* returns the short filename (8.3) for a file in Windows
*
* @param longFileName
* @return a string with the short filename, or null if an error occurred or the
* file does not exist.
*/
public static String getEightPointThree(String longFileName) {
try {
// the result
String shortName = null;
NativeCall.init();
IntCall ic = new IntCall("GetShortPathNameW");
try {
// size of result is at most the long file name (times 2 for the
// number
// of bytes)
Struct resultStruct = new Struct(longFileName.length() * 2);
int iResultCode = ic.executeCall(new Object[] { longFileName,
resultStruct, new Integer(longFileName.length()) });
if (iResultCode > 0) {
// iResultCode is length
byte[] data = resultStruct.getData();
int length = data.length > (iResultCode * 2) ? (iResultCode * 2)
: data.length;
byte[] data2 = new byte[length];
System.arraycopy(data, 0, data2, 0, length);
// structResult contains letter space letter space letter
String structResult = new String(data2);
// remove spaces in between
StringBuffer result = new StringBuffer();
for (int i = 0; i < structResult.length(); i += 2)
result.append(structResult.charAt(i));
shortName = result.toString().trim();
if (shortName.equals(""))
shortName = longFileName;
}
} finally {
ic.destroy();
}
return shortName;
} catch (Exception e) {
System.err.println("Exception of type " + e.getClass().getName()
+ ":\n" + e.getMessage());
e.printStackTrace();
}
return null;
}
}
Note that your file system must be configured to be backwards compatible with good old DOS. Windows (by default) generates a
8.3 filename for a newly created files. By setting the registry key HKEY_LOCAL_MACHINE/SYSTEM\CurrentControlSet\Control\FileSystem\NtfsDisable8dot3NameCreation however (0 to enable 8.3 name creation, or to 1 to disable), no 8.3 filenames are created anymore!
Related (just to help you find this page):