Creating Files and Folders in UWP - c#

Ive looked at at so many stackoverflow posts and articles but still didnt manage to create a file in UWP. In WPF it was really easy but UWP works differently.
I added the following in my manifest file:
<Capabilities>
<uap:Capability Name="documentsLibrary" />
</Capabilities>
Now im not sure what to do next. Inside my documents folder I have a subfolder named "Project Files". I want to create folders and files in there. How is this done in UWP? I really dont understand.

As microsoft states in their docs, its recommenced not to use the documents Library through an UWP app, instead opt for the built in storage unless its absolutely necessary.
There is an easy way to get around that if you use a folder picker
private async void buttonClick(){
FolderPicker folderPicker = new FolderPicker();
folderPicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
folderPicker.FileTypeFilter.Add("*");
StorageFolder folder= await folderPicker.PickSingleFolderAsync();
if (folder != null) {
// do Things On Folder
}
else
{
MessageDialog dialog = new MessageDialog("you selected nothing");
await dialog.ShowAsync();
}
}
The above opens up a folder select dialog, it returns the folder the user picked, its the recommended way for accessing locations outside your app's folder.
Here is how to Create a new file in this folder:
string name ="myTitle.txt";
await folder.CreateFileAsync(name, CreationCollisionOption.GenerateUniqueName);
here is how to open and write a file:
try {
StorageFile myFile = await folder.GetFileAsync(name);
await Windows.Storage.FileIO.WriteTextAsync(myFile, "myStringContent");
}
catch (Exception e)
{
Debug.WriteLine("Failure: "+e.Message);
return;
}
remember you can always avoid opening up a dialog if you use the local storage instead, it returns you app's storage folder in one line, like this:
var folder= ApplicationData.Current.LocalFolder;

I believe in UWP using the documents library is neither recommended or permitted. See https://blogs.msdn.microsoft.com/wsdevsol/2013/05/09/dealing-with-documents-how-not-to-use-the-documentslibrary-capability-in-windows-store-apps/
If you side load the app and use the documents library capability the app gets access only to declared file types, not to everything in documents.
See https://msdn.microsoft.com/en-us/library/windows/apps/hh464936.aspx#special_capabilities
Note that this special capability will not let you pass through app certification in Store, unless you go through some special procedure contacting MS first.
To create folder, use StorageFolder. To create file, use StorageFile.
See https://learn.microsoft.com/en-us/windows/uwp/files/quickstart-reading-and-writing-files

Related

Folder Picker Unauthorized access for Sub Directories and files in them UWP

I am working on a UWP application. I use the FolderPicker to select a folder on the disk. Now what I want to do is search through the entire folder and pick video files and image files and show them in a slideshow.
Below is how I use the FolderPicker to select a single folder.
FolderPicker openPicker = new FolderPicker()
{
ViewMode = PickerViewMode.Thumbnail,
SuggestedStartLocation = PickerLocationId.ComputerFolder
};
openPicker.FileTypeFilter.Add("*");
var SelectedFolder = await openPicker.PickSingleFolderAsync();
The problem I face is that event though I've picked the folder using the FolderPicker when I select a single file as StorageFile or a sub directory using a GetFolderFromPath() it throws an UnAuthorizedAccessException
System.UnauthorizedAccessException: 'Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))'
Below is how I access both of them:
StorageFolder accessFolder = StorageFolder.GetFolderFromPathAsync(SelectedFolder.Path + "\\subDir1\\subDir2").AsTask().GetAwaiter().GetResult(); // throws the exception
StorageFile file = accessFolder.GetFileAsync("DummyMediaFile.mp4").AsTask().GetAwaiter().GetResult(); // also throws the exception
There are two ways to achieve your purpose:
1. Use broadFileSystemAccess capability.
Please refer to the end of this document to add the broadFileSystemAccess capability to the package.appxmanifest file.
Looks like this:
<Package
...
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
IgnorableNamespaces="uap mp uap5 rescap">
...
<Capabilities>
<rescap:Capability Name="broadFileSystemAccess" />
</Capabilities>
Then find your application in Settings -> Application, click and select Advanced Settings, open the File system.
After that your code can be executed smoothly.
2. Don't use paths to access folders
Although the path is a relatively simple way, in UWP, it is not allowed to directly access files or folders by path. You need to use the following method:
StorageFolder accessFolder = await (await SelectedFolder.GetFolderAsync("subDir1")).GetFolderAsync("subDir2");
StorageFile file = await accessFolder.GetFileAsync("DummyMediaFile.mp4");
Note, please use this method when confirming the above file or folder name is valid, otherwise please use CreateFolderAsync("name", CreationCollisionOption.OpenIfExists)

How do you actually use FolderPicker in a UWP to grant IO access

I'm trying to do some generic database stuff with a UWP at a directory the user specifies, but I am having a nightmare with the access rights.
I've read everything I can find about the folder picker and I'm still not getting gifted access. My understanding was once the user picked a folder I could use that folder as I pleased, but it doesn't seem to be the case.
Is it as simple as I can't use Directory commands from a UWP?
Is there any documentation to show how to use FolderPicker Queries?
Am I going to have the same nightmare when I try an SQL connection?
private Windows.Storage.StorageFolder _fileAccess = null;
private async void Btn_Browse_Click(object sender, RoutedEventArgs e)
{
FolderPicker picker = new FolderPicker
{
ViewMode = PickerViewMode.List,
SuggestedStartLocation = PickerLocationId.ComputerFolder
};
picker.FileTypeFilter.Add("*");
_fileAccess = await picker.PickSingleFolderAsync();
if (_fileAccess == null)
{
return;
}
Tbx_Directory.Text = _fileAccess.Path;
StorageApplicationPermissions.FutureAccessList.
AddOrReplace("PickedFolderToken", _fileAccess);
string[] dataBases = Directory.GetFiles(_fileAccess.Path, #"*.db");
foreach (string file in dataBases ?? Enumerable.Empty<string>())
{
LBxV_Databases.Items.Add(file);
}
}
I get the access violation on the Directory use.
You are using FutureAccessList, this is a great choice, but there is a problem with the way you use it.
Here is the way to get the saved StorageFolder:
public async Task<StorageFolder> GetFolderFromAccessList(string tokenName)
{
var folder = await StorageApplicationPermissions.FutureAccessList.GetFolderAsync(tokenName);
return folder;
}
With the FolderPicker, you can get the StorageFolder object. But saving this object to the FutureAccessList does not allow you to access the folder with the path. You can only get the saved folder object by the Token which save in the FutureAccessList.
Because the UWP application is a sandbox application, when you access the database, I recommend that you save the database file in the application's local directory, such as ApplicationData.LocalFolder. You can't directly access the external file without adding special Capability.
You can find an official application example provided by Microsoft here, which demonstrates how to access files/folders persistently.
Best regards.

UWP StorageFolder access to the Downloads folder

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

UWP c# How to get a StorageFolder object of the app's download folder

I am creating files and folders using DownloadsFolder methods.
I'd like to get the parent folder as a StorageFolder instance so I can list and manipulate all the items in the app's downloads folder.
I've tried GetParentAsync() from a known StorageFile, but the return is null.
StorageFile sf = await DownloadsFolder.CreateFileAsync("testMarker");
StorageFolder dlFolder = await sf.GetParentAsync();
Is there any method to access this folder programmatically?
It seems your app doesn't has permission to read the Downloads directory. We can use GetParentAsync to get a parent the app has permissions for, but not to get folders the app doesn't have permissions in.
If we add the Music Library, Pictures Library and Videos Library to the Capabilities of the appxmanifest that we can use the GetParentAsync method to get the parent folder as a StorageFolder in these folder.
If you create a file or folder in the Downloads folder, we recommend that you add that item to your app's FutureAccessList so that your app can readily access that item in the future.
For more info, please refer the Locations Windows Store apps can access.
So if you want to get the other folders and files in DownloadsFolder, you should be able to Open files and folders with a picker.
It looks like this isn't possible - You can try to get the storage folder by using the Path with System.IO directly like so
var downloadPath = System.IO.Path.GetDirectoryName(storageFile.Path);
var downloadsFolder = await StorageFolder.GetFolderFromPathAsync(downloadPath);
But GetFolderFromPathAsync seems to throw an exception, I think windows just won't give you a reference to this folder.
A solution is to use a folder picker ONCE to pick the downloads folder (as part of the inital setup of the app). After that the app has full access to the downloads folder.
This code needs to be called once:
var folderPicker = new FolderPicker();
folderPicker.SuggestedStartLocation = PickerLocationId.Downloads;
folderPicker.FileTypeFilter.Add("*");
StorageFolder folder = await folderPicker.PickSingleFolderAsync();
if (folder != null)
{
// Application now has read/write access to all contents in the picked folder
// (including other sub-folder contents)
Windows.Storage.AccessCache.StorageApplicationPermissions.
FutureAccessList.AddOrReplace("DownloadFolderToken", folder);
var messageDialog = new MessageDialog("Download folder: " + folder.Name);
await messageDialog.ShowAsync();
}
else
{
var messageDialog = new MessageDialog("Operation cancelled");
await messageDialog.ShowAsync();
}
This code can then be used to directly access the downloads folder:
var downloadsFolder = await StorageApplicationPermissions.FutureAccessList.GetFolderAsync("DownloadFolderToken");
IReadOnlyList <StorageFile> fileList = await downloadsFolder.GetFilesAsync();
StringBuilder outputText = new StringBuilder();
outputText.AppendLine("Files:");
foreach (StorageFile file in fileList)
{
outputText.Append(file.Name + "\n");
await file.DeleteAsync();
}

Why does getting C:\ with StorageFolder GetFolderFromPathAsync return an exception?

I am using the following code
StorageFolder folder;
if (initial) folder = await StorageFolder.GetFolderFromPathAsync(#"C:\");
else { use folder picker }
and every time i try to get a Storage Drive it returns an error, what i have noticed is that if i use the Folder Picker then it doesnt throw an exception.
I am not sure what is causing this and it seems pretty irritating that my users have to specify the drive instead of my application automatically getting it.
Exception Description "Access is denied.\r\n"
In UWP you cannot list all the files/drives just like that (with official API) - this is by design, probably for security reasons. Windows Store apps are isolated and the access is only granted to limited resources/locations. In this case you are freely able to access virtual locations like MusicLibray, PicturesLibrary and so on. The list of access permisions you will find at MSDN.
When using the picker you won't get exception, hence the user has granted access to your app.
If you want to use the user folder,and you should make he pick the folder.
Windows.Storage.Pickers.FolderPicker folderPicker = new Windows.Storage.Pickers.FolderPicker();
folderPicker.ViewMode = Windows.Storage.Pickers.PickerViewMode.Thumbnail;
folderPicker.FileTypeFilter.Add(".txt");
StorageFolder folder = await folderPicker.PickSingleFolderAsync();
if (folder != null)
{
//do
}

Categories