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...).
Related
(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.
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.
I'm at the beginning of my project and I wonder which technology I should use.
In my little research I found WinRT API being kind of pleasant and I really like tile grid concept in UI.
The only problem is that my app will generate tons of data - important data - which I have to store somewhere on the local machine. By 'somewhere' I mean use of a different partition than the OS.
So, why not to try this simple code.
await Windows.Storage.PathIO.WriteTextAsync(#"d:\tests\test.txt", "Hello World");
Because E_ACCESSDENIED, that's why. Windows 8 slaps me in face screaming "Access Denied".
Is there any way I can store my data in a way I like or Win8 is too h4x0r proof?
And no, "Make a desktop application" is not a correct answer.
All you need to know about file access and permissions in Windows Store Apps.
First of all, when storing config data you have two options:
Windows.Storage.ApplicationDataContainer roamingSettings = Windows.Storage.ApplicationData.Current.RoamingSettings;
Which will use the roaming profile space so it will be stored in Cloud or Domain Profile
Windows.Storage.ApplicationDataContainer settings = Windows.Storage.ApplicationData.Current.LocalSettings;
Which will use the local profile space
Of course they both will be stored in the end under your users %appdata% but the roaming one will actually be synched if I understand everything correctly :)
So, for the application data that you would like to store on another partition:
First you need to select the location by using a FolderPicker
var folderPicker = new Windows.Storage.Pickers.FolderPicker();
//Add some other yada yada to make the picker work as needed
StorageFolder folder = await folderPicker.PickSingleFolderAsync();
Then you need to put the selected folder in an access list to remember that it's allowed to use this folder
StorageApplicationPermissions.FutureAccessList.AddOrReplace("PickedFolderToken", folder);
That way the application / system will keep track that it's allowed to use this folder in the future. The selected folder could be anywhere in the file system where you have access.
Finally if you wan't to get the selected folder back next time the app starts you simply do the opposite:
StorageFolder folder = await StorageApplicationPermissions.FutureAccessList.GetFolderAsync("TargetFolderToken",AccessCacheOptions.FastLocationsOnly);
The value FastLocationsOnly means that it will only return local drives. "TargetFolderToken" is the same identifier you used when you stored the folder in the FutureAccessList.
I use the "Sqlite for Windows Runtime" and sqlite-net (just as described at http://timheuer.com/blog/archive/2012/08/07/updated-how-to-using-sqlite-from-windows-store-apps.aspx) to develop a Windows 8 Metro-App, just . If I want to open a Database at the Program-Directory is no problem:
var dbPath = Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, "db.sqlite");
using (var db = new SQLite.SQLiteConnection(dbPath)) {
...
}
But when I want to use an extern Path like this:
var dbPath = "C:\\Users\\xxxxxx\\db.sqlite";
then an error occurs with "Cannot open database file". Why? Here I am using C#, normally I use C++, but for this problem I am sure it doesn't matter ;)
You cannot select arbitrary files on the file system. See here for details.
By default you can access these locations:
Application install directory
Application data locations
User’s Downloads folder
and
Additionally, your app can access some of the files on connected
devices by default. This is an option if your app uses the AutoPlay Device extension to launch automatically when users connect a device,
like a camera or USB thumb drive, to their system. The files your app
can access are limited to specific file types that are specified via
File Type Association declarations in your app manifest. Of course,
you can also gain access to files and folders on a removable device by
calling the file picker (using FileOpenPicker and FolderPicker) and
letting the user pick files and folders for your app to access. Learn
how to use the file picker in Quickstart: Accessing files with file pickers.
If you have the right capabilities declared you can also access:
Documents Library
Music Library
Picture Library
Videos Library
Homegroup Library
Removable devices
Media server devices (DLNA)
Universal Naming Convention (UNC) folders
A combination of the following capabilities is needed.
The home and work networks capability:
PrivateNetworkClientServer
And at least one internet and public networks capability:
InternetClient InternetClientServer
And, if applicable, the domain credentials capability:
EnterpriseAuthentication
Note You must add File Type Associations to your app manifest that declare specific file types that your app can access in this location.
In windows metro application...
It support only sandbox property of an application.
So you cant use
var dbPath = "C:\\Users\\xxxxxx\\db.sqlite";
U can only store data in local storage or application installed directory.
Please avoid to use any other path . it will not work .