Hey guys so I'm working on a program it deletes certain directories files, mostly temp files, except I get an error even know I added a catch block. The System.UnauthorizedAccessException. on the catch ioexception I get the error there:
private void DeleteInternetFiles(string internetDirectory)
{
DirectoryInfo internetTempStorage = new DirectoryInfo(internetDirectory);
try
{
//this will delete files
foreach (FileInfo getNetFileInfo in internetTempStorage.GetFiles())
{
getNetFileInfo.Delete();
}
//this will loop through and delete folders
foreach (DirectoryInfo tempDirectoryInformation in internetTempStorage.GetDirectories())
{
tempDirectoryInformation.Delete();
}
}
//catch io exception and try delete file again
catch (IOException)
{
//delete file in this directory
File.Delete(internetDirectory);
//delete folders in this directory
Directory.Delete(internetDirectory);
}
//catch access exception and delete file again
catch (UnauthorizedAccessException)
{
//delete file in this directory
File.Delete(internetDirectory);
//delete folders in this directory
Directory.Delete(internetDirectory);
}
}
And this one below is how I call the method:
if (checkBox1.Checked)
{
DeleteInternetFiles(#"C:\Users\" + Environment.UserName + #" \AppData\Local\Microsoft\Windows\Temporary Internet Files");
}
Your second call to File.Delete(internetDirectory);, inside the catch block, seems likely to be the problem. The program has already encountered an error while trying to delete the file, and then you tried again. Two things could be happening:
The user account executing the program doesn't have permission to
delete files in another user's directory.
Some file is still in use and therefore can't be deleted (e.g.
currently open in Internet Explorer.
You might want to study the responses in C# - How to Delete temporary internet files. Note the comments about possibly having to "kill IE".
The problem I see here is that the delete action you're performing requires Administrator privileges.
What you can do is try to right click > Run as Administrator the application and then perform the action.
If you want to prompt the user to elevate your application, you can do this.
Force application to Run as Administrator [Winforms only]
You get this error because the file or folder you attempt to delete have not this access right.
It may happen in your case due to some file is being currently in use while you perform a delete operation.
There are more possibilities of file being used because you delete from a folder that windows os uses for the temporary use.
Related
As a short summary, I have a string constant for a file location that includes the file name and extension such as #"C:\foldername\subfolder\filename.json. When calling File.Create from System.IO, it's creating a directory rather than the file maybe 5% of the time.
Does anyone have any insight as to what needs done different to prevent this?
if (File.Exists(fileName))
{
return File.GetLastWriteTime(fileName);
}
else
{
try
{
File.Create(fileName).Close();
return File.GetLastWriteTime(fileName);
}
catch (Exception ex)
{
Logging.sharedLogging.Log(SharedLogging.LoggingLevel.Error, "[CacheDirectoryLogic.GetOverridesLastWriteTime] Failed to create Override.json. Reason: " + ex.Message);
return null;
}
}
where fileName is #"C:\WD\Data\Cache\Override.json";
I think there should be some exception thrown, but your catch block will just log somewhere and ignore the error, so you may want to check your logger to see any exception mentioned. It will be helpful for us to understand the issue.
There are few possible root causes for the issue.
1. Permission issue
I notice the file path is in C drive. If the directory requires admin privilege to write files in the folder, it may throw access denied exception.
Tried to change the file path to D drive, which less likely has admin privilege restriction.
2. Directory is not fully created
Better practice for file creation with a full path -- check for directory existence before creating the file.
File.Create() does not create directory automatically. And it will throw error if directory is not found.
Code sample:
var directory = #"C:\WD\Data\Cache\";
var fileName = Path.Combine(directory, "Override.json");
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
if (File.Exists(fileName))
...
im trying to read a folder from a remote machine, inside this folder there are many txt files.
The machine is writing every time new datas inside the folder.
string str = "";
try
{
DirectoryInfo d = new DirectoryInfo(#"\\192.168.1.209\user\HST\");
FileInfo[] Files = d.GetFiles("*.txt");
foreach (FileInfo file in Files)
{
str = str + ", " + file.Name;
}
}
catch (Exception pp)
{
System.IO.File.WriteAllText(GlobalVariables.errorFolderLocation + "erroreLettura.1.209.txt", pp.ToString());
}
This is my code, I don't understand how to get these datas, because i get this error: "the system call level is not correct".
For example, if i try to delete the folder or a file, i get error because it's already used by another process.
So, is there a solution to "bypass" this error?
EDIT 1:
I need read every row of every file, i get the error on DirectoryInfo.
If i acces on the folders and files it works fine.
I need read this folder/files in 3 different machine, but only in this (192.168.1.209) not working, and its the only machine where i get error when i try to delete a file
Unfortunately, you are not able to delete a file which is in use by another process or delete a folder that contains a file in use, or whatever other operation that has not been specified to be accessed on the other process. In order to achieve this, the process which has the file in use, must open it with a share access, FileShare from System.IO .NET library.
I have done a ton of research on MSDN and SO but there seem to be a lot of mixed reviews on this topic and no straightforward answer. My UWP app needs to download some items for the user. It seems only logical that this goes into the "downloads" folder instead of Documents or Pictures.
What I gather from my reading is that an application is allowed to access the downloads folder and create files and sub folders within the downloads folder. However, it cannot access other files and folder (not created from your app) without the use of a picker. In this case, I should not need to use a picker because my app is using the and creating the folder for itself. I have also read, there is not need for special capabilities in the Manifest for this to work.
I can confirm that this does in fact work by creating a folder and a file in the downloads folder
StorageFile destinationFile;
StorageFolder downloadsFolder;
try
{
//Create a sub folder in downloads
try
{
downloadsFolder = await DownloadsFolder.CreateFolderAsync("AppFiles");
}
catch (Exception ex)
{
//HERE IS THE ISSUE. I get in here if the folder exists but how do i get it?
}
destinationFile = await downloadsFolder.CreateFileAsync(destination,CreationCollisionOption.GenerateUniqueName);
}
catch (FileNotFoundException ex)
{
rootPage.NotifyUser("Error while creating file: " + ex.Message, NotifyType.ErrorMessage);
return;
}
However, here is the major issue. This code works fine the first time through because the folder does not already exist and it creates it along with the file. Subsequent times through, it fails and throws an exception:
Cannot create a file when that file already exists. (Exception from HRESULT: 0x800700B7)
It does this on the line to create the folder in Downloads folder:
downloadsFolder = await DownloadsFolder.CreateFolderAsync("AppFiles");
The problem is that MSDN states that I cannot use the Collision options of "OpenIfExists" or "ReplaceExisting" which are the two collision options I would need to solve this problem. The two remaining options do no good for me. So, no matter what, it is going to throw an exception if the folder exists.
Then, the thought is that I could just catch the exception, like I am already doing in my snippet above and open the folder if it exists. The problem with this is that the "DownloadsFolder" class does not give any options to get or open a folder, only to create a folder.
So, it seems I can create the folder from my app but I cannot open or get the folder that my app created?
Thanks!
The problem with this is that the "DownloadsFolder" class does not give any options to get or open a folder, only to create a folder.
Actually, When you first run your code, you could create your folder successfully and get the folder instance to create file in this folder. But why you could not get it when it's existed, it's by design.
I believe you have checked the document:
Because the app can only access folders in the Downloads folder that it created, you can't specify OpenIfExists or ReplaceExisting for this parameter.
So, How to get the folder that you created? I will tell you in the following:)
In this case, I should not need to use a picker because my app is using the and creating the folder for itself.
As you said, the first option is to use a picker, but you've said that you do not want to use a picker. Then, I will give you another option.
When you first create the folder successfully, you could add this folder to the FutureAccessList. Then, you could get this folder directly in your code.
I've made a simple code sample for your reference:
StorageFile destinationFile;
StorageFolder downloadsFolder;
try
{
try
{
downloadsFolder = await DownloadsFolder.CreateFolderAsync("AppFiles");
string folderToken = Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.Add(downloadsFolder);
ApplicationData.Current.LocalSettings.Values["folderToken"] = folderToken;
destinationFile = await downloadsFolder.CreateFileAsync("destination.txt", CreationCollisionOption.GenerateUniqueName);
}
catch (Exception ex)
{
if (ApplicationData.Current.LocalSettings.Values["folderToken"] != null)
{
string token = ApplicationData.Current.LocalSettings.Values["folderToken"].ToString();
downloadsFolder = await Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.GetFolderAsync(token);
destinationFile = await downloadsFolder.CreateFileAsync("destination.txt", CreationCollisionOption.GenerateUniqueName);
}
}
}
catch (FileNotFoundException ex)
{
rootPage.NotifyUser("Error while creating file: " + ex.Message, NotifyType.ErrorMessage);
return;
}
I have the following method to delete a file with a provided path
private void DestroyFile(string path)
{
try
{
if (File.Exists(path))
{
File.Delete(path);
}
if (File.Exists(path))
{
throw new IOException(string.Format("Failed to delete file: '{0}'.", path));
}
}
catch (Exception ex)
{
throw ex;
}
}
I am getting the IOException that is thrown if the file exists after the File.Delete method. Specifically
System.IO.IOException): Failed to delete file: 'C:\Windows\TEMP\[FILE NAME]'.
I have also confirmed that the file does not exist at the location in the path variable after the execution is complete. I am wondering if I am running up against a race condition between the file system updating after File.Delete and checking against it again with File.Exists. Is there a better way to smoothly delete? I know that File.Delete won't return an error if the file doesn't exist so maybe these checks are a bit redundant. Should I check if the file is in use rather than if it exists at all?
Some important additional information:
The program can and does run successfully often but this particular error has been frequently seen recently.
File.Delete will mark file for deletion. File really will be deleted only when all handles to it are closed (if there are no such handles - it will always be deleted after File.Delete returns). As documented for DeleteFile winapi function (which is used by C# File.Delete):
The DeleteFile function marks a file for deletion on close. Therefore,
the file deletion does not occur until the last handle to the file is
closed
Usually there are no open handles to files you delete. Or, if there are open handles - they usually don't have "delete" share (this share allows another process to mark file for deletion), so when you try to delete such file - it either gets deleted (no open handles) or access denied or similar exception is thrown (some handles, but without delete share).
However, sometimes some software, such as antivirus or search indexer, might open arbitrary files with "delete" share and hold them for some time. If you try to delete such file - it will go without errors and file really will be deleted when that software closes its handle. However, File.Exists will return true for such "pending delete" file.
You can reproduce this issue with this simple program:
public class Program {
public static void Main() {
string path = #"G:\tmp\so\tmp.file";
// create file with delete share and don't close handle
var file = new FileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.Delete);
DestroyFile(path);
GC.KeepAlive(file);
}
private static void DestroyFile(string path) {
try {
if (File.Exists(path)) {
// no error
File.Delete(path);
}
// but still exists
if (File.Exists(path)) {
throw new IOException(string.Format("Failed to delete file: '{0}'.", path));
}
}
catch (Exception ex) {
throw ex;
}
}
}
You can retry File.Exists check forever in the program above - file will exist until you close the handle.
So that's what happens in your case - some program has open handle to this file with FileShare.Delete.
You should expect such situation. For example - just remove that File.Exists check, since you marked file for deletion and it will be deleted anyway.
while its not documented in the API, File.Delete WILL return before the file is completely deleted.
This is why you are running into the case you are having. Delete call will check for all the things that would make the delete fail (existing handle, lock, permission ect) and it will return after the initiation of Delete request
So its relatively safe to just put a while loop right after to wait until the file is gone or use a FileSystemWatcher to watch for Deleted event
File.Delete and generally most methods from System.IO are dependent on filesystem/streams/etc, whom a bit live their own lives, and are not managed resources, hence File.Delete can return before file is physically deleted, but after it's marked for deletion.
After File.Delete returns, you can be sure file will be deleted, if not this method will throw exception by itself, so second check with File.Exists and throwing IOException is unnecessary.
If you want custom exception, catch exceptions from File.Delete.
And in code attached, remember that throw ex; is diffrenent from throw; and changes stack trace to current line.
The goal is to replace a PDF-File which is currently saved on disk.
I am deleting the current PDF file from disk, then recreating a new one. This works fine unless the PDF is currently opened in the Microsoft Edge Browser.
// Try delete PDF-File (which is opened in Edge Browser)
var info = new FileInfo(pathToPdf);
if (info.Exists)
{
try
{
info.Delete();
// Same thing with the File.Delete call
//File.Delete(path);
Console.WriteLine("Success.");
}
catch (Exception)
{
Console.WriteLine("Failed.");
return;
}
}
We get a "Success" print out even though the file is opened in Edge. If it were opened in Adobe Reader it would throw an exception (File in use).
Let's create a new file. (For demonstration purposes a text file with a .pdf ending)
try
{
using (var writer = File.CreateText(pathToPdf))
{
writer.Write("Foo");
writer.Flush();
Console.WriteLine("Success.");
}
}
catch (Exception e)
{
Console.WriteLine("Failed.");
return;
}
I expected to be able to create a new file, since the Delete() didn't fail. Yet I get an UnauthorizedAccessException: "Access to the path 'XYZ' is denied."
As a workaround I can recheck if the file exists after deleting it.
var newInfo = new FileInfo(pathToPdf);
if (newInfo.Exists)
// Delete failed
But why would I need to do this? Shouldn't FileInfo.Delete() or File.Delete(path) fail in the first place?
Notes:
Tested on Windows 10 Pro with .Net Framework 4.5.1
The file is still visible in the File-Explorer with its original filesize after it was deleted by code (while opened in Edge).
When closing the Edge Browser after deleting the file by code, the file vanishes from the File-Explorer and I can create a new file programatically.
This problem occurs only with PDFs being opened in Edge. When using a Text-File instead the Text-File gets deleted properly.
Any clarification and help is appreciated.
Best Chris
If the file does not exist, FileInfo.Delete() does nothing.
From msdn
WinNt4Family
Delete does not delete a file that is open for normal I/O or a file that is memory-mapped.
You get an UnauthorizedAccessException when the path is a directory.
If FILE_SHARE_DELETE is set on the handle by Edge, then File.delete() can be called with success by another process even when the handle exists. The file is then marked for deletion and deleted after the handle is closed. Until then, it is still visible in the Explorer, but not accessible anymore.
For a more detailed explanation, see this SO post:
Odd behaviour when deleting Files with Files.delete()