UWP StorageFolder access to the Downloads folder

4

I have done a ton of research on MSDN and SO but there seem to be a lot of mixed reviews on this topic and no straightforward answer. My UWP app needs to download some items for the user. It seems only logical that this goes into the "downloads" folder instead of Documents or Pictures.

What I gather from my reading is that an application is allowed to access the downloads folder and create files and sub folders within the downloads folder. However, it cannot access other files and folder (not created from your app) without the use of a picker. In this case, I should not need to use a picker because my app is using the and creating the folder for itself. I have also read, there is not need for special capabilities in the Manifest for this to work.

I can confirm that this does in fact work by creating a folder and a file in the downloads folder

StorageFile destinationFile;
StorageFolder downloadsFolder;
try
{
   //Create a sub folder in downloads
   try
   {
         downloadsFolder = await DownloadsFolder.CreateFolderAsync("AppFiles");
   }
   catch (Exception ex)
   {
       //HERE IS THE ISSUE. I get in here if the folder exists but how do i get it?
   }

   destinationFile = await downloadsFolder.CreateFileAsync(destination,CreationCollisionOption.GenerateUniqueName);
}
catch (FileNotFoundException ex)
{
     rootPage.NotifyUser("Error while creating file: " + ex.Message, NotifyType.ErrorMessage);
     return;
}

However, here is the major issue. This code works fine the first time through because the folder does not already exist and it creates it along with the file. Subsequent times through, it fails and throws an exception:

Cannot create a file when that file already exists. (Exception from HRESULT: 0x800700B7)

It does this on the line to create the folder in Downloads folder:

downloadsFolder = await DownloadsFolder.CreateFolderAsync("AppFiles");

The problem is that MSDN states that I cannot use the Collision options of "OpenIfExists" or "ReplaceExisting" which are the two collision options I would need to solve this problem. The two remaining options do no good for me. So, no matter what, it is going to throw an exception if the folder exists.

Then, the thought is that I could just catch the exception, like I am already doing in my snippet above and open the folder if it exists. The problem with this is that the "DownloadsFolder" class does not give any options to get or open a folder, only to create a folder.

So, it seems I can create the folder from my app but I cannot open or get the folder that my app created?

Thanks!

c#
.net
uwp
windows-10
windows-10-universal

1 Answer

9

The problem with this is that the "DownloadsFolder" class does not give any options to get or open a folder, only to create a folder.

Actually, When you first run your code, you could create your folder successfully and get the folder instance to create file in this folder. But why you could not get it when it's existed, it's by design.

I believe you have checked the document:

Because the app can only access folders in the Downloads folder that it created, you can't specify OpenIfExists or ReplaceExisting for this parameter.

So, How to get the folder that you created? I will tell you in the following:)

In this case, I should not need to use a picker because my app is using the and creating the folder for itself.

As you said, the first option is to use a picker, but you've said that you do not want to use a picker. Then, I will give you another option.

When you first create the folder successfully, you could add this folder to the FutureAccessList. Then, you could get this folder directly in your code.

I've made a simple code sample for your reference:

StorageFile destinationFile;
StorageFolder downloadsFolder;
try
{

    try
    {
        downloadsFolder = await DownloadsFolder.CreateFolderAsync("AppFiles");
        string folderToken = Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.Add(downloadsFolder);
        ApplicationData.Current.LocalSettings.Values["folderToken"] = folderToken;
        destinationFile = await downloadsFolder.CreateFileAsync("destination.txt", CreationCollisionOption.GenerateUniqueName);
    }
    catch (Exception ex)
    {
        if (ApplicationData.Current.LocalSettings.Values["folderToken"] != null)
        {
            string token = ApplicationData.Current.LocalSettings.Values["folderToken"].ToString();
            downloadsFolder = await Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.GetFolderAsync(token);
            destinationFile = await downloadsFolder.CreateFileAsync("destination.txt", CreationCollisionOption.GenerateUniqueName);
        }
    }

}
catch (FileNotFoundException ex)
{
    rootPage.NotifyUser("Error while creating file: " + ex.Message, NotifyType.ErrorMessage);
    return;
}
answered on Stack Overflow Jun 9, 2018 by Xie Steven

User contributions licensed under CC BY-SA 3.0