I am facing an problem with files that I create within my application in dedicated sub folders of ApplicationData.Current.LocalFolder. I can create sub folders with ApplicationData.Current.LocalFolder.CreateFolderAsync() and even place files in it. But as soon as I try to overwrite or delete files, I get an access violation exception. (Read Access is still possible)
Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
I looked up the UWP pages but most of the time they simply create a new folder and that's it.
My attempt to overwrite the file:
public async Task WriteFileAsync(string filename, Stream fileContent)
{
StorageFolder folder = ApplicationData.Current.LocalFolder;
var deepFolders = filename.Split('/');
if (deepFolders != null)
{
for (var i=0; i<deepFolders.Length - 1; i++)
{
folder = await folder.GetFolderAsync(deepFolders[i]);
}
filename = deepFolders[deepFolders.Length - 1];
}
try
{
StorageFile oldFile = await folder.GetFileAsync(filename);
await oldFile.DeleteAsync();
}
catch (FileNotFoundException) { }
StorageFile file = await folder.CreateFileAsync(filename, CreationCollisionOption.ReplaceExisting);
}
The first time it runs just fine, but as soon as the overwrite should take place, I get the exception.
Running the whole stuff without sub-folders works like charm.
The attempt to first read and delete the file resulted in the same exception already during the deletion.
Related
When I call the following function, it should create a .txt file and write a sentence in it. It seems to execute without any errors. But I cannot find where this file is stored/located after being created. I ran a Windows Search to look for the file but nothing came up. Where is this file located? Also, what is the best folder/location to put a .txt file that the program uses? Should I put it in Solution Explorer of Visual Studio or Debug folder?
private async void CreateFile() {
try {
// Create sample file, replace if exists.
StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
StorageFile sampleFile = await storageFolder.CreateFileAsync("sample.txt", CreationCollisionOption.ReplaceExisting);
sampleFile = await storageFolder.GetFileAsync("sample.txt");
await FileIO.WriteTextAsync(sampleFile, "Swift as a shadow!");
} catch (Exception ex) {
textBox.Text = ex.ToString();
}
}
You can have the code show the path:
sampleFile = await storageFolder.GetFileAsync("sample.txt");
await new MessageDialog(sampleFile.Path).ShowAsync();
On Windows 10, this will be a path like:
C:\Users\[username]\AppData\Local\Packages\[Package family name]\LocalState\sample.txt
where username is the name of the logged on user and package family name is the package family name of your application
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 read some topic about file permission.
Someone said "App can access directories and files which the user manually selected with the FileOpenPicker or FolderPicker"
My codes are like as below:
public async void CsvParse()
{
var picker = new Windows.Storage.Pickers.FileOpenPicker();
picker.FileTypeFilter.Add(".csv");
Windows.Storage.StorageFile file = await picker.PickSingleFileAsync();
if (file != null)
{
string[] lines = File.ReadAllLines(file.Path);//this is where app stops working and gives error message.
}
}
Even when I choose file with FilePicker, it still gives me error. But when I choose file from appx folder, it works fine.
Is there a way to access other locations than app's folder?
try it this way:
public async void CsvParse()
{
var picker = new Windows.Storage.Pickers.FileOpenPicker();
picker.FileTypeFilter.Add(".csv");
Windows.Storage.StorageFile file = await picker.PickSingleFileAsync();
if (file != null)
{
IList<string> lines = await FileIO.ReadLinesAsync(file);//this is where app stops working and gives error message.
}
}
the StorageFile is the way you get access to a file. File.ReadAllLines(file.Path) you are passing a Filename, not the StorageFile but just the filepath is not enough for getting access
I am trying to write a very simple program that reads a txt file when it starts. The file is in "ApplicationData.Current.LocalFolder", as it is supposed to be something I can access without explicitly telling the user. However, after I try to check the existence of and to create the file, I receive a access denied exception at 'file.OpenStreamForReadAsync()' at the 2nd line of the second method.
The StorageFile object is passed from the checking process, so that I think I am able to avoid the situation where two objects try to open the same file. However, the problem persists.
public async Task<StorageFile> checkConfig()
{
StorageFolder localFolder = ApplicationData.Current.LocalFolder;
if (await localFolder.TryGetItemAsync("ifthen.txt") != null)
return await localFolder.GetFileAsync("ifthen.txt");
else
return await localFolder.CreateFileAsync("ifthen.txt");
}
public async void load()
{
Windows.Storage.StorageFile file = await checkConfig();
using (var input = await file.OpenStreamForReadAsync())
using (var dataReader = new StreamReader(input))
{
...
}
}
Furthermore, the problem only occurs in Release Build. Debug Build always works fine, regardless of whether the file exists or not before launching the program.
I am having some issues in my app that can download a list of music files. I'm trying to setup the following folder structure. Music Library > Artist(s) > Release Name. When starting the download, the first song's folder structure is setup properly. Once the second download starts, I always get a File Not found exception when trying to create the second sub folder (release name). Here is my code.
private async Task StartDownload(List<DownloadData> data)
{
foreach (DownloadData song in data)
{
// Set the source of the download
Uri source = new Uri(song.downloadUrl);
// Create folder stucture
StorageFolder artistFolder;
try
{
artistFolder = await KnownFolders.MusicLibrary.CreateFolderAsync(song.artistName, CreationCollisionOption.OpenIfExists);
}
catch
{
throw;
}
StorageFolder releaseFolder;
try
{
releaseFolder = await artistFolder.CreateFolderAsync(song.releaseName, CreationCollisionOption.OpenIfExists);
}
catch
{
throw; // Exception Thrown here
}
// Create file
StorageFile destinationFile;
try
{
destinationFile = await releaseFolder.CreateFileAsync(song.fileName, CreationCollisionOption.GenerateUniqueName);
}
catch
{
throw;
}
BackgroundDownloader downloader = new BackgroundDownloader();
DownloadOperation download = downloader.CreateDownload(source, destinationFile);
List<DownloadOperation> requestOperations = new List<DownloadOperation>();
requestOperations.Add(download);
await HandleDownloadAsync(download, true);
}
}
I have no idea why it works the first time around but fails on the second song.
According to the documentation for CreateFileAsync it will throw FileNotFoundExcption if
The folder name contains invalid characters, or the format of the folder name is incorrect.
So you likely need to replace invalid characters with something else like underscore.
var fixedFolderName = string.Join(
"_",
song.releaseName.Split(Path.GetInvaildFileNameChars()));