如何以编程方式派生Windows下载文件夹“%USERPROFILE%/ Downloads”?

时间:2010-09-25 18:36:44

标签: .net environment-variables registry registrykey special-folders

在.Net中,我们可以检索“特殊文件夹”的路径,例如Documents / Desktop等。今天我试图找到一种方法来获取“下载”文件夹的路径,但它看起来并不特别。< / p>

我知道我可以做'C:\ Users \ Username \ Downloads',但这似乎是一个丑陋的解决方案。那么我怎样才能使用.Net来恢复路径?

9 个答案:

答案 0 :(得分:22)

是的,这是特别的,发现这个文件夹的名称直到Vista才成为可能。 .NET仍然需要支持以前的操作系统。你可以用SHvetKnownFolderPath()来绕过这个限制,如下所示:

using System.Runtime.InteropServices;
...

public static string GetDownloadsPath() {
    if (Environment.OSVersion.Version.Major < 6) throw new NotSupportedException();
    IntPtr pathPtr = IntPtr.Zero;
    try {
        SHGetKnownFolderPath(ref FolderDownloads, 0, IntPtr.Zero, out pathPtr);
        return Marshal.PtrToStringUni(pathPtr);
    }
    finally {
        Marshal.FreeCoTaskMem(pathPtr);
    }
}

private static Guid FolderDownloads = new Guid("374DE290-123F-4565-9164-39C4925E467B");
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
private static extern int SHGetKnownFolderPath(ref Guid id, int flags, IntPtr token, out IntPtr path);

答案 1 :(得分:1)

尝试一下:

string path = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)+ @"\Downloads";

答案 2 :(得分:1)

这是accepted answer的重构,因为IMO可以更好地实现:

Utility utility = Utility.newInstance();
BasicItem item = utility.BasicList.get(0);

可以通过以下方式调用:

public static class KnownFolders
{
    public static Guid Contacts = new Guid("{56784854-C6CB-462B-8169-88E350ACB882}");
    public static Guid Desktop = new Guid("{B4BFCC3A-DB2C-424C-B029-7FE99A87C641}");
    public static Guid Documents = new Guid("{FDD39AD0-238F-46AF-ADB4-6C85480369C7}");
    public static Guid Downloads = new Guid("{374DE290-123F-4565-9164-39C4925E467B}");
    public static Guid Favorites = new Guid("{1777F761-68AD-4D8A-87BD-30B759FA33DD}");
    public static Guid Links = new Guid("{BFB9D5E0-C6A9-404C-B2B2-AE6DB6AF4968}");
    public static Guid Music = new Guid("{4BD8D571-6D19-48D3-BE97-422220080E43}");
    public static Guid Pictures = new Guid("{33E28130-4E1E-4676-835A-98395C3BC3BB}");
    public static Guid SavedGames = new Guid("{4C5C32FF-BB9D-43B0-B5B4-2D72E54EAAA4}");
    public static Guid SavedSearches = new Guid("{7D1D3A04-DEBB-4115-95CF-2F29DA2920DA}");
    public static Guid Videos = new Guid("{18989B1D-99B5-455B-841C-AB7C74E4DDFC}");

    static Dictionary<string, Guid> Map { get; } = new Dictionary<string, Guid> {
        { nameof(Contacts), Contacts },
        { nameof(Desktop), Desktop },
        { nameof(Documents), Documents },
        { nameof(Downloads), Downloads },
        { nameof(Favorites), Favorites },
        { nameof(Links), Links },
        { nameof(Music), Music },
        { nameof(Pictures), Pictures },
        { nameof(SavedGames), SavedGames },
        { nameof(SavedSearches), SavedSearches },
        { nameof(Videos), Videos },
    };

    public static string GetPath(string knownFolder,
        KnownFolderFlags flags = KnownFolderFlags.DontVerify, bool defaultUser = false) =>
        Map.TryGetValue(knownFolder, out var knownFolderId)
            ? GetPath(knownFolderId, flags, defaultUser)
            : ThrowUnknownFolder();

    public static string GetPath(Guid knownFolderId, 
        KnownFolderFlags flags=KnownFolderFlags.DontVerify, bool defaultUser=false)
    {
        if (SHGetKnownFolderPath(knownFolderId, (uint)flags, new IntPtr(defaultUser ? -1 : 0), out var outPath) >= 0)
        {
            string path = Marshal.PtrToStringUni(outPath);
            Marshal.FreeCoTaskMem(outPath);
            return path;
        }
        return ThrowUnknownFolder();
    }

    //[DoesNotReturn]
    static string ThrowUnknownFolder() => 
        throw new NotSupportedException("Unable to retrieve the path for known folder. It may not be available on this system.");

    [DllImport("Shell32.dll")]
    private static extern int SHGetKnownFolderPath(
        [MarshalAs(UnmanagedType.LPStruct)]Guid rfid, uint dwFlags, IntPtr hToken, out IntPtr ppszPath);
}

或者有时更方便的使用字符串来获取它:

var downloadPath = KnownFolders.GetPath(KnownFolders.Downloads);

答案 3 :(得分:0)

您的第一个答案的问题是,如果默认的下载目录已更改为[Download1],它会给您错误的结果!覆盖所有可能性的正确方法是

using System;
using System.Runtime.InteropServices;

static class cGetEnvVars_WinExp    {
    [DllImport("Shell32.dll")] private static extern int SHGetKnownFolderPath(
        [MarshalAs(UnmanagedType.LPStruct)]Guid rfid, uint dwFlags, IntPtr hToken,
        out IntPtr ppszPath);

    [Flags] public enum KnownFolderFlags : uint { SimpleIDList = 0x00000100
        , NotParentRelative = 0x00000200, DefaultPath = 0x00000400, Init = 0x00000800
        , NoAlias = 0x00001000, DontUnexpand = 0x00002000, DontVerify = 0x00004000
        , Create = 0x00008000,NoAppcontainerRedirection = 0x00010000, AliasOnly = 0x80000000
    }
    public static string GetPath(string RegStrName, KnownFolderFlags flags, bool defaultUser) {
        IntPtr outPath;
        int result = 
            SHGetKnownFolderPath (
                new Guid(RegStrName), (uint)flags, new IntPtr(defaultUser ? -1 : 0), out outPath
            );
        if (result >= 0)            {
            return Marshal.PtrToStringUni(outPath);
        } else {
            throw new ExternalException("Unable to retrieve the known folder path. It may not "
                + "be available on this system.", result);
        }
    }

}   

要测试它,如果您特别需要个人下载目录,则将默认设置为false - &gt;

using System.IO;
class Program    {
    [STAThread]
    static void Main(string[] args)        {
        string path2Downloads = string.Empty;
        path2Downloads = 
            cGetEnvVars_WinExp.GetPath("{374DE290-123F-4565-9164-39C4925E467B}", cGetEnvVars_WinExp.KnownFolderFlags.DontVerify, false);
        string[] files = { "" };
        if (Directory.Exists(path2Downloads)) {
            files = Directory.GetFiles(path2Downloads);
        }
    }//Main
}

或者只是一行Environment.ExpandEnvironmentVariables() - &gt; (最简单的解决方案)。

using System.IO;
class Program    {
/* https://ss64.com/nt/syntax-variables.html */
    [STAThread]
    static void Main(string[] args)        {
        string path2Downloads = string.Empty;
        string[] files = { "" };
        path2Downloads = Environment.ExpandEnvironmentVariables(@"%USERPROFILE%\Downloads");
        if (Directory.Exists(path2Downloads)) {
            files = Directory.GetFiles(path2Downloads);
        }
    }//Main
}

答案 4 :(得分:0)

我使用了下面的代码,它适用于Windows 7及更高版本的.net 4.6。 以下代码提供了用户个人资料文件夹路径-> "C:\Users\<username>"

string userProfileFolder = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);

接下来要访问下载文件夹,只需组合其他路径字符串,如下所示:

string DownloadsFolder = userProfileFolder + "\\Downloads\\";

现在,最终结果将是

"C:\Users\<username>\Downloads\"

希望它可以节省将来某人的时间。

答案 5 :(得分:0)

汉斯的回答完美无缺!我很欣赏这是一个非常古老的问题,但看到 .Net(无论出于何种原因)仍然没有填补这个功能漏洞,我想我会发布下面对 Han 的答案的重构,以防有人觉得它有用。

  • 添加了一些缺失的错误处理
  • 通过属性而不是方法访问​​文件夹,即与其他 .Net 环境使用(例如 Environment.CurrentDirectory)一致

复制/粘贴片段..

=SUMIFS($D$2:$D$13,$B$2:$B$13,B17)+SUMIFS($D$2:$D$13,$B$2:$B$13,B18)+SUMIFS($D$2:$D$13,$B$2:$B$13,B19)

使用

using System;
using System.IO;
using System.Runtime.InteropServices;

namespace Utils
{
    public static class SpecialFolder
    {
        public static string Downloads => _downloads ??= GetDownloads();

        // workaround for missing .net feature SpecialFolder.Downloads
        // - https://stackoverflow.com/a/3795159/227110
        // - https://stackoverflow.com/questions/10667012/getting-downloads-folder-in-c
        private static string GetDownloads()
        {
            if (Environment.OSVersion.Version.Major < 6)
                throw new NotSupportedException();

            var pathPtr = IntPtr.Zero;
            try
            {
                if (SHGetKnownFolderPath(ref _folderDownloads, 0, IntPtr.Zero, out pathPtr) != 0)
                    throw new DirectoryNotFoundException();
                return Marshal.PtrToStringUni(pathPtr);
            }
            finally
            {
                Marshal.FreeCoTaskMem(pathPtr);
            }
        }

        [DllImport("shell32.dll", CharSet = CharSet.Auto)]
        private static extern int SHGetKnownFolderPath(ref Guid id, int flags, IntPtr token, out IntPtr path);

        private static Guid _folderDownloads = new Guid("374DE290-123F-4565-9164-39C4925E467B");
        private static string _downloads;
    }
}

答案 6 :(得分:-1)

尝试:

Dim Dd As String = Environment.GetFolderPath(Environment.SpecialFolder.Favorites)
Dim downloD As String = Dd.Replace("Favorites", "Downloads")
txt1.text = downLoD

这只是一个技巧,而不是解决方案。

答案 7 :(得分:-1)

这并不难。如果要在vb.net中获得downloads文件夹目录,只需执行以下步骤:

1。添加一个名为Special_Direcories的标签。

2。加载表单时添加以下代码:

Special_directories.Text = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) & "\downloads\"

这会将标签文本设置为用户文件夹路径和“ \ downloads \”。 它将是这样的:

C:\ users \ USERFOLDER \ downloads \

答案 8 :(得分:-3)

对于VB,请尝试...

Dim strNewPath As String = IO.Path.GetDirectoryName(Environment.GetFolderPath(Environment.SpecialFolder.Desktop)) + "\Downloads\"