How to get short-filenames in Windows using Java?
Asked Answered
O

2

10

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).

Othelia answered 19/9, 2013 at 11:23 Comment(3)
I think this thread could be useful: https://mcmap.net/q/53865/-how-can-i-read-all-files-in-a-folder-from-javaChattel
This thread is useful as it highlights how to use JNA (Java(tm) Native Access) to access the Windows Win32 API function GetShortPathName() : #11039095Othelia
This thread details using command-line in the same way: #10227644Othelia
O
10

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;
}
Othelia answered 19/9, 2013 at 11:23 Comment(1)
The solution is very good but has a small bug. The fileName.toUpperCase() should remove the toUpperCase since that conversion might do some conversion that is not compatible with how windows charset works. In return windows might not find the file. I had errors with a filename like "20140506_224702_Bäckerstraße.jpg" which through conversion became "20140506_224702_BÄCKERSTRASSE.JPG".Henryson
G
-1

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
Gobbler answered 11/7, 2020 at 21:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.