I'm trying to make a UWP app which can export a file saved in his own storage into the document library.
In Package.appxmanifest I've inserted the following lines:
<uap:Capability Name="picturesLibrary" />
<uap:Capability Name="documentsLibrary" />
The code to get the path is this:
StorageFolder storageFolder = await KnownFolders.GetFolderForUserAsync(null /* current user */, KnownFolderId.DocumentsLibrary);
string path = storageFolder.Path + "\\" + fileName;
The code to save the file is this:
FileStream writer = new FileStream(filePath, FileMode.Create);
At this point, the program launches this exception:
Access to the path 'C:\Users\luca9\AppData\Roaming\Microsoft\Windows\Libraries\Documents.library-ms' is denied.
On my 950XL, the exception is similar:
Access to the path 'C:\Data\Users\DefApps\APPDATA\ROAMING\MICROSOFT\WINDOWS\Libraries\Documents.library-ms' is denied.
I've tryied both on Documents and Pictures libraries, but I get the same exception.
How can I solve it?
Thank you in advance,
Luca
Don't get FileStream with path - the app doesn't have privileges. As you already have StorageFolder, use it to create a StorageFile and then get stream from it with one of its methods, for example:
var file = await storageFolder.CreateFileAsync("fileName");
using (var stream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
// do what you want
}
this example from Microsoft works with uwp.
https://learn.microsoft.com/en-us/windows/uwp/files/quickstart-save-a-file-with-a-picker
1. Create and customize the FileSavePicker
var savePicker = new Windows.Storage.Pickers.FileSavePicker();
savePicker.SuggestedStartLocation =
Windows.Storage.Pickers.PickerLocationId.DocumentsLibrary;
// Dropdown of file types the user can save the file as
savePicker.FileTypeChoices.Add("Plain Text", new List<string>() { ".txt" });
// Default file name if the user does not type one in or select a file to replace
savePicker.SuggestedFileName = "New Document";
2. Show the FileSavePicker and save to the picked file
Windows.Storage.StorageFile file = await savePicker.PickSaveFileAsync();
if (file != null)
{
// Prevent updates to the remote version of the file until
// we finish making changes and call CompleteUpdatesAsync.
Windows.Storage.CachedFileManager.DeferUpdates(file);
// write to file
await Windows.Storage.FileIO.WriteTextAsync(file, file.Name);
// Let Windows know that we're finished changing the file so
// the other app can update the remote version of the file.
// Completing updates may require Windows to ask for user input.
Windows.Storage.Provider.FileUpdateStatus status =
await Windows.Storage.CachedFileManager.CompleteUpdatesAsync(file);
if (status == Windows.Storage.Provider.FileUpdateStatus.Complete)
{
this.textBlock.Text = "File " + file.Name + " was saved.";
}
else
{
this.textBlock.Text = "File " + file.Name + " couldn't be saved.";
}
}
else
{
this.textBlock.Text = "Operation cancelled.";
}
Related
I'm trying to save my text file in UWP, but It always saving to different file. By the way I'm using MVVM architecture.
My Code
FileSavePicker savePicker = new FileSavePicker();
savePicker.SuggestedFileName = "New Text Document";
savePicker.SuggestedStartLocation = PickerLocationId.Desktop;
savePicker.FileTypeChoices.Add("Text Document", new List<string>() { ".txt" });
savePicker.DefaultFileExtension = ".txt";
StorageFile storageFile = await savePicker.PickSaveFileAsync();
if(storageFile != null)
{
CachedFileManager.DeferUpdates(storageFile);
await FileIO.WriteTextAsync(storageFile, Document.Text);
FileUpdateStatus updateStatus = await CachedFileManager.CompleteUpdatesAsync(storageFile);
Document.FileName = savePicker.SuggestedFileName;
Document.IsSaved = true;
}
My code is always saving texts on different file. I'm trying to save my text to same file.
In UWP there is a feature called FutureAccessList. It can be used to save the token of the file, opened with the FilePicker. When you now want to save it again you can retrive the StorageFile by the token and write to it.
Add a FileToken property to your Document class:
public string FileToken { get; set; }
Now when you pick your file you add the file to the FutureAccessList:
...
StorageFile storageFile = await savePicker.PickSaveFileAsync();
if (storageFile != null)
{
CachedFileManager.DeferUpdates(storageFile);
await FileIO.WriteTextAsync(storageFile, Document.Text);
FileUpdateStatus updateStatus = await CachedFileManager.CompleteUpdatesAsync(storageFile);
Document.FileName = savePicker.SuggestedFileName;
Document.IsSaved = true;
//Add the file to the FutureAccessList to get it back later
Document.FileToken = StorageApplicationPermissions.FutureAccessList.Add(storageFile);
}
To retrive the file and save it again:
public async void SaveFile()
{
//Get the file back from the FutureAccessList by its token and write to it
StorageFile file = await StorageApplicationPermissions.FutureAccessList.GetFileAsync(Document.FileToken);
await FileIO.WriteTextAsync(file, Document.Text);
}
Now when you e.g. save your Document class to Json and retrive it after the app restarts you can still use the FileToken to write to the file. There is no need to let the user pick it again using the SaveFilePicker.
When the code above is to complicated or there is no need for this (I don't know what you need this for), you can put a StorageFile propertie directly to your Document class and put the file, that the SaveFilePicker returned in it. But this won't work when restarting the app. The user would always have to pick the file again.
I'm trying to add multiple files to an already created ZIP file using PickMultipleFilesAsync(). I previously created the ZIP file I want to access in the same code using FilesavePicker.PickSaveFileAsync() method. The app is running on Windows 10 Pro version 1803 in Laptop PC, and I used Visual Studio Community 2017 to create it.
The problem I get is that, after following steps described in the FileOpenPicker MSDN page, I get a System.UnauthorizedAccessException: 'Access to the path 'C:\Users\'User'\Downloads{ZIP file}' is denied.'
I created ZIP file and tried to add new files using this code:
StorageFile file = await savePicker.PickSaveFileAsync();
if (file != null)
{
// Prevent updates to the remote version of the file until we finish making changes and call CompleteUpdatesAsync.
CachedFileManager.DeferUpdates(file);
try
{
Stream stream = await file.OpenStreamForWriteAsync();
using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Update))
{
// This line works fine, file is added
archive.CreateEntryFromFile(path_to_another_file, file_name_in_ZIP);
//....
var dialog = new MessageDialog("Do you want to add more files to ZIP?");
//... (dialog configuration for Yes/No options)
var result = await dialog.ShowAsync();
if(result.Label == "Yes")
{
Debug.WriteLine("Yes option was selected!");
// Include additional files
var openPicker = new FileOpenPicker();
openPicker.FileTypeFilter.Add("*");
openPicker.SuggestedStartLocation = PickerLocationId.Downloads;
IReadOnlyList<StorageFile> addedFiles = await openPicker.PickMultipleFilesAsync();
if (addedFiles.Count > 0)
{
// Application now has read/write access to the picked file(s)
foreach (StorageFile addedFile in addedFiles)
{
Debug.WriteLine(addedFile.Path); // No problem here
// I get the UnauthorizedAccessException here:
archive.CreateEntryFromFile(addedFile.Path, #"additional files/" + addedFile.Name);
}
}
else
{
// Update log file
globalLog += GetTime() + "No additional files";
}
}
}
}
}
I already added <rescap:Capability Name="broadFileSystemAccess"/> to appxmanifest just in case, but as I had access to selected files using FileOpenPicker I think that is not the problem.
As I created the ZIP file within this code I should still have access to it, right? I suspect that FileOpenPicker somehow "closes" access to ZIP file in order to give access to files to be added, or that MessageDialog prevents of accessing the ZIP file I created after I called showAsync().
Is there any other way to achieve what I'm trying?
EDIT: I can not access the file(s) I select using FileOpenPicker, despite I can show file name(s) in Debug console. ZIP file access is OK.
I just found a solution. As stated here, you can use a buffer to stream file contents to ZIP file, just replace:
// I get the UnauthorizedAccessException here:
archive.CreateEntryFromFile(addedFile.Path, #"additional files/" + addedFile.Name);
With:
ZipArchiveEntry readmeEntry = archive.CreateEntry(#"additional files/" + addedFile.Name);
byte[] buffer = WindowsRuntimeBufferExtensions.ToArray(await FileIO.ReadBufferAsync(addedFile));
using (Stream entryStream = readmeEntry.Open())
{
await entryStream.WriteAsync(buffer, 0, buffer.Length);
}
That way, files are added and no UnauthorizedAccessException happens. Hope this helps anyone with the same problem!
I am new to Xamarin. I have simple app; Where I have notes field and take picture functionality. I am using media plugin to take pictures. The picture obviously get saved in phone gallery.
But I also wanted to save the text file which contains the input from notes field in phone.
I am struggling to save the text file.
The is the product structure. I am using shared project.
File structure and classes image
Sample app image
I have an save button. What I want to do is when save button is clicked; save the text file which has user input from notes field.
Here is action of my save button
I was looking on this website
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/files?tabs=windows
I tried some code but nothing worked.
private async void Take_Photo_Button_Clicked(object sender, EventArgs e)
{
await CrossMedia.Current.Initialize();
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
await DisplayAlert("No Camera", ":( No camera available.", "OK");
return;
}
var file = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
{
SaveToAlbum = true,
Name = jobnoentry.Text + "-" + Applicationletterentry + "-" + signnoentry.Text + "-" + SignType,
});
if (file == null)
return;
MainImage.Source = ImageSource.FromStream(() =>
{
var stream = file.GetStream();
return stream;
});
//Save text field
string fileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "temp.txt");
File.WriteAllText(fileName, "Hello World");
}
First, where exactly a file gets saved depends on the platform, but you can always print the string for the filename to see the actual path, e.g.
string fileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "temp.txt");
Console.WriteLine(filename); // will write the actual path to the application output.
In any case the path you are using, Environment.SpecialFolder.LocalApplicationData, will save the text file to a location only accessible by the app itself, you won't see it in a file browser. If you need to have the text files available outside of your app, how to do that will vary based on platform and you will need to use a dependency service to get the correct file paths.
However you can verify if you have saved and can read a file as follows:
string fileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "temp.txt");
File.WriteAllText(fileName, "Hello World");
The above is code from your post. If you don't get an exception, chances are it worked. To verify:
var text = File.ReadAllText(filename);
if (text == "Hello World")
Console.WriteLine("File contents verified and correct");
else
Console.WriteLine("File contents do not match saved string");
I am looking for a way to append strings-text to a file in a Windows Store App. I have tried reading the file and then creating a new one to overwrite it but Windows Store Apps C# does not work like C where when creating a new file with the same name overwrites the old one. Currently my code is opening the old file, reading it's contents, deleting it and creating a new one with the content I read plus the content I wish to append.
I know there is a better way but I cannot seem to find it. So How may I append text to an already existent file in a Windows Store App (Windows RT)?
EDIT--
I tried this
var folder = Windows.ApplicationModel.Package.Current.InstalledLocation;
var file = await folder.GetFileAsync("feedlist.txt");
await Windows.Storage.FileIO.AppendTextAsync(file, s);
but I keep getting System.UnauthorizedAccessException
according to MSDN this happens when the file is readonly (I checked with right click properties, it's not) and if I do not have the necessary privileges to access the file
what should I do?
You can use the FileIO class to append to a file. For example ...
// Create a file in local storage
var folder = ApplicationData.Current.LocalFolder;
var file = await folder.CreateFileAsync("temp.txt", CreationCollisionOption.FailIfExists);
// Write some content to the file
await FileIO.WriteTextAsync(file, "some contents");
// Append additional content
await FileIO.AppendTextAsync(file, "some more text");
Check out the File Access Sample for more examples.
Using FileIO.AppendTextAsync is a good option.
Please find the code snippet for this.
First it creates a folder, if not exists. Otherwise it will not create.
Then it creates a file if not exists.
Finally appending the text in the file.
public static async void WriteTrace(TraceEventType eventType, string msg, [CallerMemberName] string methodName = "")
{
const string TEXT_FILE_NAME = "Trace.txt";
string logMessage = eventType.ToString() + "\t" + methodName + "\t" + msg ;
IEnumerable<string> lines = new List<string>() { logMessage };
StorageFolder localFolder = ApplicationData.Current.LocalFolder;
StorageFolder tempFolder = ApplicationData.Current.TemporaryFolder;
//if(localFolder.CreateFolderQuery(Windows.Storage.Search.CommonFolderQuery.)
StorageFolder LogFolder = await localFolder.CreateFolderAsync("LogFiles", CreationCollisionOption.OpenIfExists);
await LogFolder.CreateFileAsync(TEXT_FILE_NAME, CreationCollisionOption.OpenIfExists);
StorageFile logFile = await LogFolder.GetFileAsync(TEXT_FILE_NAME);
await FileIO.AppendLinesAsync(logFile, lines);
}
I am looking for a way to append strings-text to a file in a Windows Store App. I have tried reading the file and then creating a new one to overwrite it but Windows Store Apps C# does not work like C where when creating a new file with the same name overwrites the old one. Currently my code is opening the old file, reading it's contents, deleting it and creating a new one with the content I read plus the content I wish to append.
I know there is a better way but I cannot seem to find it. So How may I append text to an already existent file in a Windows Store App (Windows RT)?
EDIT--
I tried this
var folder = Windows.ApplicationModel.Package.Current.InstalledLocation;
var file = await folder.GetFileAsync("feedlist.txt");
await Windows.Storage.FileIO.AppendTextAsync(file, s);
but I keep getting System.UnauthorizedAccessException
according to MSDN this happens when the file is readonly (I checked with right click properties, it's not) and if I do not have the necessary privileges to access the file
what should I do?
You can use the FileIO class to append to a file. For example ...
// Create a file in local storage
var folder = ApplicationData.Current.LocalFolder;
var file = await folder.CreateFileAsync("temp.txt", CreationCollisionOption.FailIfExists);
// Write some content to the file
await FileIO.WriteTextAsync(file, "some contents");
// Append additional content
await FileIO.AppendTextAsync(file, "some more text");
Check out the File Access Sample for more examples.
Using FileIO.AppendTextAsync is a good option.
Please find the code snippet for this.
First it creates a folder, if not exists. Otherwise it will not create.
Then it creates a file if not exists.
Finally appending the text in the file.
public static async void WriteTrace(TraceEventType eventType, string msg, [CallerMemberName] string methodName = "")
{
const string TEXT_FILE_NAME = "Trace.txt";
string logMessage = eventType.ToString() + "\t" + methodName + "\t" + msg ;
IEnumerable<string> lines = new List<string>() { logMessage };
StorageFolder localFolder = ApplicationData.Current.LocalFolder;
StorageFolder tempFolder = ApplicationData.Current.TemporaryFolder;
//if(localFolder.CreateFolderQuery(Windows.Storage.Search.CommonFolderQuery.)
StorageFolder LogFolder = await localFolder.CreateFolderAsync("LogFiles", CreationCollisionOption.OpenIfExists);
await LogFolder.CreateFileAsync(TEXT_FILE_NAME, CreationCollisionOption.OpenIfExists);
StorageFile logFile = await LogFolder.GetFileAsync(TEXT_FILE_NAME);
await FileIO.AppendLinesAsync(logFile, lines);
}