I'm getting access denied when using
StorageFile.GetFileFromPathAsync(filePath)
From other posts and some documentation that I read UWP can only access to video lib, videos, (profile related folders) when declared in the Package.appxmanifest etc...
With FilePicker I have no problem accessing these locations, but the StorageFile.GetFileFromPathAsync was to automatically load those files into a list when the page loads.
How can I use this function to load files outside known folders video lib, videos, etc.
You can only use this method to access files on those safe paths UWP apps have access to. If you get access to another location via a file or folder picker, you must cache access to it using Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList. This API allows you to store an existing instance of StorageFile or StorageFolder and gives you a "token", which is a string by which you can later access the selected StorageItem again.
StorageFile file = await savePicker.PickSaveFileAsync();
if (file != null)
{
string faToken = StorageApplicationPermissions.FutureAccessList.Add(file);
}
Now that the file is in FutureAccessList, you can later retrieve it:
StorageFile file = await StorageApplicationPermissions.FutureAccessList.GetFileAsync(faToken);
Items stored in FutureAccessList survive even when the app is closed and reopened so it is probably the ideal solution for your use case. However, keep in mind the FutureAccessList can store at most 1000 items (see Docs), and you must maintain it - so if you no longer need an item, make sure you delete it, so that it does not count towards the limit anymore.
The second solution would be to declare the broadFileSystemAccess capability. This is however a restricted capability and your app must have a good reason to use it.
Related
I have been looking for a way to know the status of Hidden attribute of StorageFile object. As far as I have read the docs, the FileAttributes property does not have the Hidden attribute. Any workaround?
There are two file access APIs in UWP. The newer one, built for UWP is Windows.Storage, which includes StorageFile as you mentioned. This is specifically built for this sandboxed scenario where the app has limited access to the filesystem. In this case, the Hidden attribute is really not available and Hidden files are even not listed when calling StorageFolder.GetFilesAsync() etc. The main advantage of Storage APIs is that they are built as asynchronous and that they can cover scenarios like user picked folder - to which you then get a temporary permission by virtue of the specific StorageFolder instance.
The second API set is the old and trusted System.IO file API, that provides a lot more control and includes the control over Hidden attribute. The disadvantage is that by default you can access only the app's install and AppData locations with this API, unless your app declares the Broad file system access API or App alias, which are new features in Windows 10 April 2018 update and later.
I tried to find a solution that works for UWP storage files, that are not necessarily located in a known directory (such as app folder, downloads, pictures etc.).
For known directories you can create a new instance of FileInfo with the path of the file, and its attributes property will tell you whether the file is hidden or not.
Unfortunately, this solution won't apply for files outside of the known directories, as asking for the attributes of the FileInfo instance will throw an unauthorized access exception (or something similar).
I did find a solution that works for checking the hidden attribute for files located in various parts of the file system, assuming you have access to the requested file's StorageFile object:
public bool isHidden(StorageFile file) {
var extendedFileAttributes = "System.FileAttributes";
uint hiddenAttributeValue = (uint) FileAttributes.Hidden;
IDictionary<string, object> retrievedProperties =
await file.Properties.RetrievePropertiesAsync(new List<string> { extendedFileAttributes });
var attributes = retrievedProperties[extendedFileAttributes];
if (attributes != null)
{
return (((uint)attributes & hiddenAttributeValue) == hiddenAttributeValue));
}
return false;
}
Retrieving extended file properties:
https://learn.microsoft.com/en-us/windows/uwp/files/quickstart-getting-file-properties
Strings to retrieve:
https://learn.microsoft.com/en-us/windows/win32/properties/core-bumper
I try to make a photo editor/viewer as the Windows 10 App. I let the user to open an image file by FileOpenPicker. The program also should be able to browse other images from the same folder as the selected file (e.g. by previous and next buttons), but there is the problem. I even can't get file names of these images.
All the methods I have tried just return null...
// File picker to let user select the image file - works OK
var picker = new Windows.Storage.Pickers.FileOpenPicker();
picker.FileTypeFilter.Add(".jpg");
var file = await picker.PickSingleFileAsync();
// These methods to get neighboring files do not work
// 1. using Directory.GetFiles - it returns empty string
string filePaths[] = Directory.GetFiles(Path.GetDirectoryName(file.Path));
// 2. using GetParentAsync - it returns null instead of file's parent folder
var folder = await file.GetParentAsync();
var files = await folder.GetFilesAsync();
So, how can I browse through the other files from the same folder as the already opened file?
I have found I can use a FolderPicker to get access to given folder, but that would be a very silly solution if the user need to go through two pickers (one for the image file and another for the actual file's folder).
EDIT: After I checked Removable Storage and Picture Library in App Manifest, the GetParentAsync started to work for USB drives, but when I open an image file from any local drive it still returns null. Why it does not work for local HDD drives, which are the logical storage device for large amount of photos? Storing data only to user folders on small SSD system drive or USB drive is so limiting.
Basically, If user pick a 'File' by FilePicker, you have the rights only for the 'File'. Not for parent folder. (If you have access rights for picture library and the file is located at the library, you can access the folder. But, the rights comes from library access, not from the file.)
This is a design of WinRT's file accessing rule via FileBroker.. It's hard to overcome.
My recommendation (and many of storeapp picture viewer choose this way, including my app PICT8) is, Ask user to set the folder that the user mainly used to keep the image files by using FolderPicker.
You can keep the access rights for the folder by using FAL or MRU. Instead of using FilePicker, You can show the list of files to your user.
StorageApplicationPermissions class
And...My answer for another thread may help you also: Access all files in folder from FileActivated file
You got a StorageFile from the FileOpenPicker. You can get the containing folder with the GetParentAsync method and then call GetFilesAsync to get the files inside the folder.
var folder = await file.GetParentAsync();
var files = await folder.GetFilesAsync();
var next = files.SkipWhile(x => x.Name == file.Name)
.Skip(1)
.First();
As you can see you can get the next file inside the folder be skipping ech file until you find your current. Then skip it and take the first after your file.
I think it would better to order the files before you acccess them by calling OrderBy respectivly OrderByDescending on the files result.
You are able to pass a lambda expression to select an property or value for sorting.
I've been at this for a few days and been fighting with this for two years. Roughly, I have an App where the user opens a file, edits for a long period of time and then saves or suspends until later. I have an automatic save feature that works, but, I want an auto-archiving feature too (in case the user wants to auto-save to a backup file, and not overwrite the current file).
Roughly speaking, I want to create a new file when a file is being edited, hopefully where the original file is. However, I've quickly given that up as Microsoft will not allow access to Skydrive, other directories, etc for writing without explicit picker access.
However, I thought maybe I could use the Documents Library. But any use here seems to give me the NullReferenceException. Here's a sample of what I was trying (noting that .ged files are associated with my App):
string backupFileName = openStorageFile + "-backup.ged";
StorageFolder currentFolder;
StorageFile fileCopy;
try
{
// try to set up Backup file in the same directory as the source file
currentFolder = await selectedFile.GetParentAsync();
fileCopy = await openStorageFile.CopyAsync(currentFolder, backupFileName, NameCollisionOption.ReplaceExisting);
// Success return
return;
}
catch
{
// The failed... try something else
Debug.WriteLine("INFO: Failed to set up backup file in the source file's directory, trying backup option");
}
try
{
// try to set up Backup file in the same directory as the source file
fileCopy = await openStorageFile.CopyAsync(KnownFolders.DocumentsLibrary, backupFileName, NameCollisionOption.ReplaceExisting);
}
catch
{
// The failed... try something else
Debug.WriteLine("INFO: Failed to set up backup file in the source document library, no other option available");
}
}
So roughly, The first the first call for GetParentAsync form the original file works. But CopyAsync to that directory fails with NullReferenceException.
The second try uses DocumentsLibrary.which also fails on CopyAsync with a NullReferenceException.
I tried this:
Windows 8 StorageFile.GetFileFromPathAsync Using UNC Path
According to MSDN, I shouldn't have an issue as long as my App is associated with .ged files (and it is). Is there anything else to try?
You need to add the documentsLibrary capability for access to the documents library. This capability is discouraged and is not exposed in Visual Studio's manifest designer. You'll have to edit the package.appxmanifest's xml directly
<Capabilities>
<Capability Name="internetClient" />
<Capability Name="documentsLibrary" />
</Capabilities>
I confirmed that your code saves to the documents library once I added that and fixed backupFileName setter to use the openStorageFile's Name. From the other references in the code openStorageFile is a StorageFile not a string.
string backupFileName = openStorageFile.Name + "-backup.ged";
See the Special use capabilities section of the capabilities documentation for more restrictions on using documents library if you need the app to be certified for the store rather than side-loaded.
I would save the backup in the app's local data rather than in the documents library. The app can expose a way to restore from the backup to a picked location when the user needs it.
How to get a StorageFolder from a user-friendly (localized) path?
Folders can have a user-friendly (localized) name. The name can be read via:
StorageFolder.DisplayName
Example: The Folder 'C:\Users' is shown on a 'German' Windows as 'C:\Benutzer'.
I would like to get the StorageFolder from a user-friendly path like the Windows Explorer. However, calling the following method throws an exception:
var folder = await StorageFolder.GetFolderFromPathAsync(#"C:\Benutzer");
Is there some support in WinRT API to achieve this?
Edit: I'm not explicitly answering the localised part of your question, but it's entirely possible that you're falling foul of a permissions issue that I describe below.
It's not possible in WinRT to access the file system** without it being user initiated.
The mechanism they have in WinRT for what you're describing is to ask the user to pick the location via a folder picker, then to add that chosen folder to the FutureAccessList for programmatic access later.
StorageFile folder = await folderPicker.PickSingleFolderAsync();
folderToken = Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.Add(folder);
//Keep this folder token to access the folder programmatically later
You can access that folder later using the following.
StorageFolder folder = await StorageApplicationPermissions.FutureAccessList.GetFolderAsync(folderID);
Note that there's absolutely no exception handling in this example. Check the links (particularly the latter) for more details.
** As in your example, however there are standard folder / file resources you can access without this.
you can get the StorageFolder located into app install path - Package.Current.InstalledLocation.Path by specifying the path manually, for example you downloaded a folder with subfolders and you want to get a file from there, you'll use:
StorageFolder customAppFolder = await StorageFolder.GetFolderFromPathAsync(Package.Current.InstalledLocation.Path + #"\yourFolder\yourSubfolder");
now you can iterate files in that subfolder:
IReadOnlyList<StorageFile> filesInFolder =await appFolder.GetFilesAsync();
foreach (StorageFile file in filesInFolder){
Debug.WriteLine(file.Name);
}
I am writing an app for Windows 8 metro and I need to be able to open/create files of any type.
However, according to this article, even if an app declares that the documentsLibrary capability, it can only open/create files that are defined in the file type associations section.
How can I allow my app to open or create files of any type?
No. That page only refers to access to files without user's knowledge. That means you can enumerate them and read them without user explicitly selecting one.
When using Windows.Storage.Pickers.FileOpenPicker, user can select any file from anywhere. But this must be done by user, not automatically by application. Same thing with saving.
Example: Access and save files using the file picker sample
It seems that without adding any capabilities, the app is allowed to create any type of file in the "Downloads" folder.
This code works, even without the documentsLibrary capability:
StorageFolder folder = await Windows.Storage.DownloadsFolder.CreateFolderAsync("folder");
StorageFile file = await folder.CreateFileAsync("myfile.txt");
The ".txt" file type did not need to be declared in the file type associations.
Update: this article on msdn explains the permissions for the download folder.