在C#中获取下载文件夹?

85

我编写了一些代码,用于搜索目录并在列表框中显示文件。

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

然而,当它说Users\Hunter时——实际上,当人们获取我的软件时,他们的名字并不是Hunter。那么,如何自动检测用户的“下载”文件夹?

我已经尝试了这个:

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);
}

但是我遇到了一个错误。


1
也许可以使用 Environment.SpecialFolder 枚举?你尝试过 path = Path.GetDirectoryName(Environment.GetFolderPath(Environment.SpecialFolder.Personal)); path = Path.Combine(path, "Downloads"); 吗? - Kiquenet
@Kiquenet 不要那样做,看看我的答案。 - Ray
6个回答

177

下载文件夹是一个所谓的“已知”文件夹,与文档、视频和其他文件夹一起。

不要:

  • 组合硬编码路径段以检索已知文件夹路径
  • 假设已知文件夹是用户文件夹的子文件夹
  • 滥用长时间未使用的存储过时路径的注册表键

已知文件夹可以在其属性表中重定向到任何位置。我几年前在我的 CodeProject 文章中详细介绍了这一点。

要:

  • 使用 WinAPI 方法 SHGetKnownFolderPath ,因为它是检索这些路径的预期和唯一正确的方法。

您可以像以下方式调用它(我仅提供了涵盖新用户文件夹的几个 GUID):

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);
}

这是一个检索“下载”文件夹路径的示例:

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

NuGet软件包

如果你不想自己进行p/invoke操作,请查看我的NuGet软件包(请注意,用法不同,请查看其自述文件)。


2
这个类在vs2015中似乎无法工作 - 它抱怨GetPath没有3个参数 - 这是正确的,在代码中没有提到。 - BugFinder
这个也有一个由微软最初创建的NuGet,类似的SO答案中提到:https://dev59.com/lmsz5IYBdhLWcg3wxax3#12610045 - Robb Sadler
使用带有LOGON32_LOGON_INTERACTIVE的模拟器无法正常工作,Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)SHGetKnownFolderPath返回<0。注意:用户可能已将文件夹移动到另一个位置(在8、8.1和10中非常容易)。 - Kiquenet
现状行为:Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)返回_C:\Users\Myusername_。使用模拟代码(带有LogonType LOGON32_LOGON_INTERACTIVE)返回_空字符串_。 - Kiquenet

13

最简单的方法是:

Process.Start("shell:Downloads");

如果您只需要获取当前用户的下载文件夹路径,您可以使用以下方法:

我从 @PacMani 的代码中提取了它。

 // 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();
}

10
这个关键字包含一个带有名称为“!不要使用此注册表项”的不祥的键和值为“请改用SHGetFolderPath或SHGetKnownFolderPath函数”的内容。该关键字是由微软开发者雷蒙德·陈("微软的查克·诺里斯")添加进来的。“!不要使用此注册表项”消息为何会出现在注册表中?Shell Folders关键字之长且悲哀的故事 - Kiquenet
2
请勿使用此注册表键在.NET中获取所有“特殊文件夹” - Kiquenet

5

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

这段代码是用于获取当前用户的下载文件夹路径。

4
这是一个只有代码的回答,我们希望得到更好的回答。技术说明:这将在国际版Windows上出现错误。问题的被接受答案是正确的做法,可以在所有版本的Windows上运行。 - rene
3
在我看来,最好删除这个答案,因为它没有用。这不是一个好的答案,因为Downloads不是value Specialfolder enum,而且只有在EN-*系统上使用"\Downloads"才有效。而且用户可以更改位置。详细解释请参见在.NET中获取所有“特殊文件夹” - Kiquenet
3
这个答案是完全错误的。虽然特殊文件夹“Downloads”的默认值是用户配置文件主目录下名为“Downloads”的文件夹,但用户很容易将“Downloads”特殊文件夹更改为他们有访问权限的任何其他位置。上述方法对于已修改“Downloads”特殊文件夹目标的任何用户都不起作用。 - Peter Duniho
3
这会在我的电脑上出问题。我的电脑有一个固态硬盘和一个机械硬盘。因此,虽然用户配置文件在C:上,但桌面、下载、文档、图片、音乐、视频文件夹都在D:驱动器上,纯粹为了存储空间。个人认为这不是一个好答案。 - Scott
1
@WiiLF 这也是最不正确的一个。 - Ray
显示剩余4条评论

3

注意:
如果您更改了下载文件夹,则SHGetKnownFolderPath将返回错误的值。

唯一能够返回正确值的是在Windows上读取shell-folders注册表键374DE290-123F-4565-9164-39C4925E467B

现在,您可以使用“不要使用此注册表键”或获取错误的值。
您决定哪个更好。

跨平台版本:

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
        )
    );
}

4
该注册表键包含一个名为“!Do not use this registry key”的不祥之钥和值“Use the SHGetFolderPath or SHGetKnownFolderPath function instead”,该键由微软开发人员雷蒙德·陈("Microsoft's Chuck Norris")创建。为什么注册表中会有“!Do not use this registry key”的消息? Shell Folders键的漫长而悲伤的故事 - Kiquenet
2
不要使用此注册表键。[在.NET中获取所有“特殊文件夹”] - Kiquenet
3
这个答案是完全错误的。虽然特殊文件夹“Downloads”的默认值是用户配置文件主目录下名为“Downloads”的文件夹,但用户很容易将“Downloads”特殊文件夹更改为他们有访问权限的任何其他位置。上述方法对于已修改“Downloads”特殊文件夹目标的任何用户都不起作用。 - Peter Duniho
1
@Peter Duniho:实际上,我已经修改了“下载”目标,这就是我编写代码的原因。这是在.NET 2.0中唯一有效的方法。其他方法都不行,或者会得到错误的结果。 - Stefan Steiger
5
在Unix系统中,没有类似于Windows自定义的“下载”文件夹,因此您需要硬编码一个文件夹名称。而在Windows中,您应该调用SHGetKnownFolderPath()函数,但实际上您会尝试直接从注册表中获取文件夹。无论哪种情况,这个答案都是无用的,并且对使用它的人有潜在的危害。 - Peter Duniho
显示剩余7条评论

-2
通常情况下,您的软件应该有一个可配置的变量来存储用户的下载文件夹,可以由用户分配,并在未设置时提供默认值。您可以将该值存储在应用程序配置文件或注册表中。
然后,在您的代码中从存储位置读取该值。

1
在我看来,最好删除那些没有用的回答。因为“重复造轮子”的回答并不好。只需要使用WinAPI而不是App.config即可获取所有“特殊文件夹”在.NET中获取所有“特殊文件夹” - Kiquenet

-4

等一下,当我把它放到我的代码中时,我会得到一个错误:无法找到路径的一部分'C:\Users\Hunter\Documents\Visual Studio 2010\Projects\Setup Mover2\Setup Mover2\bin\Debug\UserProfile\Downloads'。 - Hunter Mitchell
2
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)) + "\Downloads"; // 我的错,抱歉 - Marduk
3
@Marduk 请删除您的评论,因为它们提供的解决方案只适用于英语系统,而且甚至也只有一部分能够使用。 - Roland Illig
4
我的看法是,建议删除答案,因为它没有用。这不是一个好的答案,因为Downloads不是值Specialfolder枚举,并且仅在英文系统上使用"\Downloads"有效。此外,用户可以更改位置。有关获取.NET中所有“特殊文件夹”的完整说明,请参阅在.NET中获取所有“特殊文件夹” - Kiquenet
2
较新的文件夹,自Windows Vista以来存在,未在SpecialFolder枚举中列出。 MSDN中发布的特殊文件夹列表 - Kiquenet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接