Get the user download folder path

I’d like to share my recent discovery about the user download folder. At first sight, it seems like a trivial question. But believe me, it’s not.

So buckle up, and join me for a journey in uncharted Windows registry waters..

What I have been doing for years, and that everyone is doing is this :

Paths.get(System.getProperty("user.home"), "Downloads");

Basically, we are targetting the downloads folder for the current user. This is simple and working. But did you know that you can actually change the default download folder on Windows? I learnt that because one of my client was doing it and an issue was raised.

The procedure is explained here :

I then tried to seek an environment variable or a Java variable allowing me to retrieving that new download path. But it was nowhere to be seen! I launched Chrome, and saw that it was able to retrieve that new path. How the hell was it doing?

Long story short, I plunged into Chrome source code to find that :

// Return a default path for downloads that is safe.
// We just use 'Downloads' under DIR_USER_DOCUMENTS. Localizing
// 'downloads' is not a good idea because Chrome's UI language
// can be changed.
bool GetUserDownloadsDirectorySafe(FilePath* result) {
  if (!GetUserDocumentsDirectory(result))
    return false;

  *result = result->Append(L"Downloads");
  return true;

// On Vista and higher, use the downloads known folder. Since it can be
// relocated to point to a "dangerous" folder, callers should validate that the
// returned path is not dangerous before using it.
bool GetUserDownloadsDirectory(FilePath* result) {
  typedef HRESULT (WINAPI *GetKnownFolderPath)(
  GetKnownFolderPath f = reinterpret_cast<GetKnownFolderPath>(
      GetProcAddress(GetModuleHandle(L"shell32.dll"), "SHGetKnownFolderPath"));
  base::win::ScopedCoMem<wchar_t> path_buf;
  if (f && SUCCEEDED(f(FOLDERID_Downloads, 0, NULL, &path_buf))) {
    *result = FilePath(std::wstring(path_buf));
    return true;
  return GetUserDownloadsDirectorySafe(result);

Apparently, sneaky Chrome is directly calling a method on shell32.dll. If we pull the string a little bit, we see that Chrome is calling SHGetKnownFolderPath function which use a KNOWNFOLDERID.

And if we scroll a little bit, what do we find?

So here it is! Our lord, our savior, I’m speaking of the world famous
guid in the registry! Joke aside, here are some snippets allowing you to retrieve the default download folder on Windows knowing all that :

import com.sun.javafx.PlatformUtil;
import com.sun.jna.platform.win32.Advapi32Util;
import com.sun.jna.platform.win32.WinReg;

     * Return the default folder for downloads of the current user by looking
     * into the registry key.
     * @return
    public static String getDefaultDownloadFolder() {
        try {
            if (PlatformUtil.isWindows()) {
                return Advapi32Util.registryGetStringValue(WinReg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders", "{374DE290-123F-4565-9164-39C4925E467B}");
            } else {
                return null;
        } catch (Exception ex) {
            LOGGER.error("Problem when reading in registry", ex);
        return null;

My method is looking into the registry for the default download folder. If nothing is found, then we can fallback on the common solution described at the very top.

I know this is quite ugly, but frankly, I have not found better way to do so. Can we also call the windows dll directly with Java? And also, what about other platforms like Mac? If you have a better solution or anything, please comment and share.


2 thoughts on “Get the user download folder path”

  1. Not sure if it’s all that much of a better way to do it, but I use “Runtime.getRuntime().exec()” with “reg query” and the same registry path/key you pointed to. This at least avoids need for JNA.

Leave a Reply

Your email address will not be published. Required fields are marked *