Getting Downloads Folder in C#?

164.9k Views Asked by At

I have made some code that will search directories and display files in a listbox.

DirectoryInfo dinfo2 = new DirectoryInfo(@"C:\Users\Hunter\Downloads");
FileInfo[] Files2 = dinfo2.GetFiles("*.sto");
foreach (FileInfo file2 in Files2)
{
     listBox1.Items.Add(file2.Name);
}

However, where it says Users\Hunter - well, when people get my software, their name is not Hunter. So how can I automatically detect the user's Downloads folder?

I have tried this:

string path = Environment.SpecialFolder.UserProfile + @"\Downloads";
DirectoryInfo dinfo2 = new DirectoryInfo(Environment.SpecialFolder.UserProfile + path);
FileInfo[] Files2 = dinfo2.GetFiles("*.sto");
foreach (FileInfo file2 in Files2)
{
     listBox1.Items.Add(file2.Name);
}

I get an error though.

6

There are 6 best solutions below

4
On BEST ANSWER

The Downloads folder is a so called "known" folder, together with Documents, Videos, and others.

Do NOT:

  • combine hardcoded path segments to retrieve known folder paths
  • assume known folders are children of the user folder
  • abuse a long deprecated registry key storing outdated paths

Known folders can be redirected anywhere in their property sheets. I've gone into more detail on this several years ago in my CodeProject article.

Do:

  • use the WinAPI method SHGetKnownFolderPath as it is the intended and only correct method to retrieve those paths.

You can p/invoke it as follows (I've provided only a few GUIDs which cover the new user folders):

public enum KnownFolder
{
    Contacts,
    Downloads,
    Favorites,
    Links,
    SavedGames,
    SavedSearches
}

public static class KnownFolders
{
    private static readonly Dictionary<KnownFolder, Guid> _guids = new()
    {
        [KnownFolder.Contacts] = new("56784854-C6CB-462B-8169-88E350ACB882"),
        [KnownFolder.Downloads] = new("374DE290-123F-4565-9164-39C4925E467B"),
        [KnownFolder.Favorites] = new("1777F761-68AD-4D8A-87BD-30B759FA33DD"),
        [KnownFolder.Links] = new("BFB9D5E0-C6A9-404C-B2B2-AE6DB6AF4968"),
        [KnownFolder.SavedGames] = new("4C5C32FF-BB9D-43B0-B5B4-2D72E54EAAA4"),
        [KnownFolder.SavedSearches] = new("7D1D3A04-DEBB-4115-95CF-2F29DA2920DA")
    };

    public static string GetPath(KnownFolder knownFolder)
    {
        return SHGetKnownFolderPath(_guids[knownFolder], 0);
    }

    [DllImport("shell32",
        CharSet = CharSet.Unicode, ExactSpelling = true, PreserveSig = false)]
    private static extern string SHGetKnownFolderPath(
        [MarshalAs(UnmanagedType.LPStruct)] Guid rfid, uint dwFlags,
        nint hToken = 0);
}

Here's an example of retrieving the path of the Downloads folder:

string downloadsPath = KnownFolders.GetPath(KnownFolder.Downloads);
Console.WriteLine($"Downloads folder path: {downloadsPath}");

NuGet Package

If you don't want to p/invoke yourself, have a look at my NuGet package (note that the usage is different, please check its README).

9
On

string download = Environment.GetEnvironmentVariable("USERPROFILE")+@"\"+"Downloads";

5
On

http://msdn.microsoft.com/en-us//library/system.environment.specialfolder.aspx

There are the variables with the path to some special folders.

1
On

typically, your software shall have a configurable variable that stores the user's download folder, which can be assigned by the user, and provide a default value when not set. You can store the value in app config file or the registry.

Then in your code read the value from where it's stored.

10
On

Note:
SHGetKnownFolderPath will return the WRONG value if you changed the download-folder.

The only thing that will ever return you the correct value is reading the shell-folders registry-key 374DE290-123F-4565-9164-39C4925E467B on Windows.

Now you can either use the "!Do not use this registry key", or you can get the wrong value.
You decide which is better for you.

Cross-Platform version:

public static string GetHomePath()
{
    // Not in .NET 2.0
    // System.Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
    if (System.Environment.OSVersion.Platform == System.PlatformID.Unix)
        return System.Environment.GetEnvironmentVariable("HOME");

    return System.Environment.ExpandEnvironmentVariables("%HOMEDRIVE%%HOMEPATH%");
}


public static string GetDownloadFolderPath()
{
    if (System.Environment.OSVersion.Platform == System.PlatformID.Unix)
    {
        string pathDownload = System.IO.Path.Combine(GetHomePath(), "Downloads");
        return pathDownload;
    }

    return System.Convert.ToString(
        Microsoft.Win32.Registry.GetValue(
             @"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
            ,"{374DE290-123F-4565-9164-39C4925E467B}"
            ,String.Empty
        )
    );
}
2
On

The easiest way is:

Process.Start("shell:Downloads");

If you only need to get the current user's download folder path, you can use this:

I extracted it from @PacMani 's code.

 // using Microsoft.Win32;
string GetDownloadFolderPath() 
{
    return Registry.GetValue(@"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders", "{374DE290-123F-4565-9164-39C4925E467B}", String.Empty).ToString();
}