(c# UWP) How to read files in any directory without using file selectors?
This is my code:
var t = Task.Run(() => File.ReadAllText(#"D:\chai.log"));
t.Wait();
Thrown exception:
Access to the path 'D:\chai.log' is denied.
Thanks!
Windows 10 Build 17093 introduced broadFileSystemAccess capability which allows apps to access folders which the current user has access to.
This is a restricted capability. On first use, the system will prompt
the user to allow access. Access is configurable in Settings > Privacy
File system. If you submit an app to the Store that declares this capability, you will need to supply additional descriptions of why
your app needs this capability, and how it intends to use it. This
capability works for APIs in the Windows.Storage namespace
MSDN Documentation
broadFileSystemAccess
Windows.Storage
Access to user's files and folders are denied. In a UWP app, only the files or folders that are picked by the user can be accessed to read or write.
To show a dialog for the user to pick files or folders, write this code below:
var picker = new Windows.Storage.Pickers.FileOpenPicker();
picker.FileTypeFilter.Add(".log");
Windows.Storage.StorageFile file = await picker.PickSingleFileAsync();
if (file != null)
{
// Application now has read/write access to the picked file
}
Read Open files and folders with a picker - UWP app developer | Microsoft Docs for more details of the FileOpenPicker.
If you want future access to the files or folders the user picked this time, use MostRecentlyUsedList to track these files and folders.
Windows.Storage.StorageFile file = await picker.PickSingleFileAsync();
var mru = Windows.Storage.AccessCache.StorageApplicationPermissions.MostRecentlyUsedList;
string mruToken = mru.Add(file, "Some log file");
And you can enumerate your mru later to access the files or folders in the future:
foreach (Windows.Storage.AccessCache.AccessListEntry entry in mru.Entries)
{
string mruToken = entry.Token;
string mruMetadata = entry.Metadata;
Windows.Storage.IStorageItem item = await mru.GetItemAsync(mruToken);
// The type of item will tell you whether it's a file or a folder.
}
Read Track recently used files and folders - UWP app developer | Microsoft Docs for more details of the MostRecentlyUsedList.
Related
I'm working on my first WinRT app and I do not seem to be able to find any code that would allow me to loop through a directory and get file names that are in that directory?
I have found plenty of code to do it in a normal winform, wpf and console but nothing really for the Winrt variety.
The closest I've come to code:
Uri dataUri = new Uri("ms-appx:///DataModel/SampleData.json");
But that just seems to get files that are withinn my own project?
How would I go about scanning a normal directory like "c:\something\something"?
I'm working on my first WinRT app and I do not seem to be able to find any code that would allow me to loop through a directory and get file names that are in that directory?
If you want to loop through a directory within UWP, you could use GetFilesAsync to get a file list from a directory.
However, UWP run sandboxed and have very limited access to the file system. For the most part, they can directly access only their install folder and their application data folder. Access to other locations is available only through a broker process.
You could access #"c:\something\something"via FileOpenPicker or FolderPicker.
var picker = new Windows.Storage.Pickers.FileOpenPicker();
picker.ViewMode = Windows.Storage.Pickers.PickerViewMode.Thumbnail;
picker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.PicturesLibrary;
picker.FileTypeFilter.Add(".jpg");
picker.FileTypeFilter.Add(".jpeg");
picker.FileTypeFilter.Add(".png");
Windows.Storage.StorageFile file = await picker.PickSingleFileAsync();
if (file != null)
{
// Application now has read/write access to the picked file
}
else
{
}
And this is official tutorial you could refer to.
I am able to delete/move/copy storage files successfully when I get file objects through filepicker. But, When user drops files from windows file explorer into my app, I am unable to delete/move those files (but it allows me to copy). My code is..
if (e.DataView.Contains(StandardDataFormats.StorageItems) == false) { return; }
var files = await e.DataView.GetStorageItemsAsync();
if (files.Count < 0) { return; }
foreach (var file in files)
{
await file.DeleteAsync(StorageDeleteOption.PermanentDelete);
//await file.MoveAsync(folder, Filename, NameCollisionOption.GenerateUniqueName);
}
When I try to delete/move I get the following error.
"WinRT information: This file is restricted to read access and may not be modified or deleted". But the file is not read-only. It allows me to add the same file through file picker!
It's by design. You could not delete files when you drop files. UWP apps have direct access only to their own files.
The Picker is completely different from the "drag and drop" operation.
The picker runs with the user’s full privileges, and it can use these privileges on the app’s behalf for locations the app has requested via capabilities, locations requested by the user via file pickers, etc. The StorageItem encapsulates this brokerage procedure so the app doesn’t need to deal with it directly. From Rob's blog.
In my console application I use
var allFiles = Directory.EnumerateFiles(directoryPath, "*.*", SearchOption.AllDirectories).ToList();
to return the path of each file in a folder (and in all sub-folders).
However in UWP, using the same thing returns 0
FolderPicker folderPicker = new FolderPicker();
folderPicker.SuggestedStartLocation = PickerLocationId.ComputerFolder;
folderPicker.FileTypeFilter.Add("*");
StorageFolder pickedFolder = await folderPicker.PickSingleFolderAsync();
var allFiles = Directory.EnumerateFiles(pickedFolder.Path, "*.*", SearchOption.AllDirectories).ToList();
I've made a method that uses the GetFilesAsync() and GetFolderAsync() functions but it is no where near as quick as Directory.EnumerateFiles()
private async Task GetFilesInFolders(ObservableCollection<string> list, StorageFolder parent)
{
foreach (var file in await parent.GetFilesAsync())
{
list.Add(file.Path);
}
foreach (var folder in await parent.GetFoldersAsync())
{
await GetFilesInFolders(list, folder);
}
}
Why does Directory.EnumerateFiles() returns 0 files?
Unlike the traditional desktop application, UWP runs sandboxed and have very limited access to the file system.
By default the UWP can only access its Local Folder like the LocalFolder/InstallationFolder... or the files and folders in the user's Downloads folder that your app created, if apps need to access others fils, we may need to use capabilities or file picker. For more information, please see File access permissions
Why does Directory.EnumerateFiles() returns 0 files?
UWP app has no direct access to the folder by using the pickedFolder.Path if the pickedFolder is not in the app's local folder. If you pick the folder from the app's local folder, your code will work fine.
Besides, using the path in the UWP may not be a good practice, it does not work for the KnownFolders like the musiclibrary,videolibrary..as well. For more information, please refer to Rob's blog: Skip the path: stick to the StorageFile.
It is recommend to use a FolderPicker to let the user pick the folder and add it to your app's FutureAccessList or MostRecentlyUsedList, in this way the they can be reloaded later without requiring the user to go through the picker. For more information, please check: How to track recently-used files and folders.
I´m developing an app that is reading jpeg and pdf files from a configurable location on the filesystem.
Currently there is a running version implemented in WPF and now I´m trying to move to the new Windows Universal apps.
The following code works fine with WPF:
public IList<string> GetFilesByNumber(string path, string number)
{
if (string.IsNullOrWhiteSpace(path))
throw new ArgumentNullException(nameof(path));
if (string.IsNullOrWhiteSpace(number))
throw new ArgumentNullException(nameof(number));
if (!Directory.Exists(path))
throw new DirectoryNotFoundException(path);
var files = Directory.GetFiles(path, "*" + number + "*",
SearchOption.AllDirectories);
if (files == null || files.Length == 0)
return null;
return files;
}
With using Universal Apps I ran into some problems:
Directory.Exists is not available
How can I read from directories outside of my app storage?
To read from an other directory outside the app storage I tried the following:
StorageFolder folder = StorageFolder.GetFolderFromPathAsync("D:\\texts\\");
var fileTypeFilter = new string[] { ".pdf", ".jpg" };
QueryOptions queryOptions = new QueryOptions(CommonFileQuery.OrderBySearchRank, fileTypeFilter);
queryOptions.UserSearchFilter = "142";
StorageFileQueryResult queryResult = folder.CreateFileQueryWithOptions(queryOptions);
IReadOnlyList<StorageFile> files = queryResult.GetFilesAsync().GetResults();
The thing is: It isn´t working, but I get an exception:
An exception of type 'System.UnauthorizedAccessException' occurred in TextManager.Universal.DataAccess.dll but was not handled in user code
Additional information: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
I know that you have to configure some permissions in the manifest, but I can´t find one suitable for filesystem IO operations...
Did someone also have such problems/a possible solution?
Solution:
From the solutions that #Rico Suter gave me, I chosed the FutureAccessList in combination with the FolderPicker. It is also possible to access the entry with the Token after the program was restarted.
I can also recommend you the UX Guidlines and this Github sample.
Thank you very much!
In UWP apps, you can only access the following files and folders:
Directories which are declared in the manifest file (e.g. Documents, Pictures, Videos folder)
Directories and files which the user manually selected with the FileOpenPicker or FolderPicker
Files from the FutureAccessList or MostRecentlyUsedList
Files which are opened with a file extension association or via sharing
If you need access to all files in D:\, the user must manually pick the D:\ drive using the FolderPicker, then you have access to everything in this drive...
UPDATE:
Windows 10 build 17134 (2018 April Update, version 1803) added additional file system access capabilities for UWP apps:
Any UWP app (either a regular windowed app or a console app) that declares an AppExecutionAlias is now granted implicit access to the files and folders in the current working directory and downward, when it’s activated from a command line. The current working directory is from whatever file-system location the user chooses to execute your AppExecutionAlias.
The new broadFileSystemAccess capability grants apps the same access to the file system as the user who is currently running the app without file-picker style prompts. This access can be set in the manifest in the following manner:
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
...
IgnorableNamespaces="uap mp uap5 rescap">
...
<Capabilities>
<rescap:Capability Name="broadFileSystemAccess" />
</Capabilities>
These changes and their intention are discussed at length in the MSDN Magazine article titled Universal Windows Platform - Closing UWP-Win32 Gaps. The articles notes the following:
If you declare any restricted capability, this triggers additional
scrutiny at the time you submit your package to the Store for
publication. ... You don’t need an AppExecutionAlias if you have this
capability. Because this is such a powerful feature, Microsoft will
grant the capability only if the app developer provides compelling
reasons for the request, a description of how this will be used, and
an explanation of how this benefits the user.
further:
If you declare the broadFileSystemAccess capability, you don’t need to
declare any of the more narrowly scoped file-system capabilities
(Documents, Pictures or Videos); indeed, an app must not declare both
broadFileSystemAccess and any of the other three file-system
capabilities.
finally:
Even after the app has been granted the capability, there’s also a
runtime check, because this constitutes a privacy concern for the
user. Just like other privacy issues, the app will trigger a
user-consent prompt on first use. If the user chooses to deny
permission, the app must be resilient to this.
The accepted answer is no longer complete. It is now possible to declare broadFileSystemAccess in the app manifest to arbitrarily read the file system.
The File Access Permissions page has details.
Note that the user can still revoke this permission via the settings app.
You can do it from UI in VS 2017.
Click on manifest file -> Capabilities -> Check photo library or whatever stuff you want.
According to MSDN doc : "The file picker allows an app to access files and folders, to attach files and folders, to open a file, and to save a file."
https://msdn.microsoft.com/en-us/library/windows/apps/hh465182.aspx
You can read a file using the filepicker through a standard user interface.
Regards
this is not true:
Files which are opened with a file extension association or via sharing
try it, by opening files from mail (outlook) or from the desktop...
it simply does not work
you first have to grant the rights by the file picker.
so this ist sh...
This is a restricted capability. Access is configurable in Settings > Privacy > File system. and enable acces for your app. Because users can grant or deny the permission any time in Settings, you should ensure that your app is resilient to those changes. If you find that your app does not have access, you may choose to prompt the user to change the setting by providing a link to the Windows 10 file system access and privacy article. Note that the user must close the app, toggle the setting, and restart the app. If they toggle the setting while the app is running, the platform will suspend your app so that you can save the state, then forcibly terminate the app in order to apply the new setting. In the April 2018 update, the default for the permission is On. In the October 2018 update, the default is Off.
More info
I am working on an app that will run on all Windows 8 devices (RT support a must) and I am working on adding some offline capabilities, but I can't figure out how to download to a removable storage device such as a USB drive or, in the case of a Surface RT, the micro SD card. Ideally I would like to be able to have the user specify the directory, but it may end up downloading hundreds of files so it has to be specified just once, not once per file. I also want to avoid requiring the user to manually configure libraries.
I have found plenty of articles about how to download to the various libraries, but those go to the internal storage and thus has very limited space on a Surface RT. How can I have the user specify a location for a large number of files to download and/or download to a removable storage device?
A really slick solution would be a way to programmatically create a library in a location of the user's choosing so the user can choose if they want it on the local system or on a removable device.
I appreciate any suggestions.
You should take advantage of FutureAccessList. It allows you to reuse files and folders that the user has previously granted you access to.
First the user will select the target folder using a FolderPicker:
var picker = new FolderPicker();
picker.FileTypeFilter.Add("*");
var folder = await picker.PickSingleFolderAsync();
You then add the folder to FutureAccessList and get back a string token which you can store for later use (e.g. to ApplicationData.LocalSettings):
var token = StorageApplicationPermissions.FutureAccessList.Add(folder);
When you want to download a file, first get the folder from FutureAccessList and create the target file:
var folder = await StorageApplicationPermissions.FutureAccessList
.GetFolderAsync(token);
var file = await folder.CreateFileAsync(filename);
With that data you can create a DownloadOperation:
var downloader = new BackgroundDownloader();
var download = downloader.CreateDownload(uri, file);
From here on proceed as if you were downloading to any other location (start the download, monitor progress...).