i have written some pdf files to a temp directory and these get displayed as a thumbnail that the user can view. when i close my form i clean up all of the files in the temp directory.
If however the user has one of the thumbnails open and then closes my application - it deletes the files and then throws an exception because the pdf is open in another process and cant be cleaned up.
I guess this is a shocking programming decision by me, but i am still a novice! How should i account for this in my code?
Thanks
You can detect if the file is in use by using code similar to below, then use that to warn the user that a file can't be deleted.
Unfortunately you can't delete a file that is in use.
public static bool IsFileInUse(string pathToFile)
{
if (!System.IO.File.Exists(pathToFile))
{
// File doesn't exist, so we know it's not in use.
return false;
}
bool inUse = false;
System.IO.FileStream fs;
try
{
fs = System.IO.File.Open(pathToFile, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Read, System.IO.FileShare.None);
fs.Close();
}
catch (System.IO.IOException ex)
{
string exMess = ex.Message;
inUse = true;
}
return inUse;
}
You should catch that exception (in catch block you can inform user to close that file or it will not be deleted), and if the temp directory is yours you can try to delete it when application starts (or when it ends again), if its windows temp directory, then it does not matter that much
Tools like File Unlocker can release a file. However I think this could make programs depending on the file crash...
Maybe you can look up how they unlock files or manage to execute the unlocker via Process.Start to unlock your file and delete it.
However if it's you blocking the file you should try and fix this in your programm. Maybe you should dispose all loaded files (filestreams etc) before trying to clean it up.
Related
Every time I save a file and delete it right away using the function below, I keep getting this error message: "System.IO.IOException: The process cannot access the file because it is being used by another process".
Waiting for a couple of minutes or closing visual studio seems to only unlock the files that you uploaded previously.
public static bool DeleteFiles(List<String> paths)
{ // Returns true on success
try
{
foreach (var path in paths)
{
if (File.Exists(HostingEnvironment.MapPath("~") + path))
File.Delete(HostingEnvironment.MapPath("~") + path);
}
}
catch (Exception ex)
{
return false;
}
return true;
}
I think that the way I'm saving the files may cause them to be locked. This is the code for saving the file:
if (FileUploadCtrl.HasFile)
{
filePath = Server.MapPath("~") + "/Files/" + FileUploadCtrl.FileName;
FileUploadCtrl.SaveAs(filePath)
}
When looking for an answer I've seen someone say that you need to close the streamReader but from what I understand the SaveAs method closes and disposes automatically so I really have no idea whats causing this
After some testing, I found the problem. turns out I forgot about a function I made that was called every time I saved a media file. the function returned the duration of the file and used NAudio.Wave.WaveFileReader and NAudio.Wave.Mp3FileReader methods which I forgot to close after I called them
I fixed these issues by putting those methods inside of a using statement
Here is the working function:
public static int GetMediaFileDuration(string filePath)
{
filePath = HostingEnvironment.MapPath("~") + filePath;
if (Path.GetExtension(filePath) == ".wav")
using (WaveFileReader reader = new WaveFileReader(filePath))
return Convert.ToInt32(reader.TotalTime.TotalSeconds);
else if(Path.GetExtension(filePath) == ".mp3")
using (Mp3FileReader reader = new Mp3FileReader(filePath))
return Convert.ToInt32(reader.TotalTime.TotalSeconds);
return 0;
}
The moral of the story is, to check if you are opening the file anywhere else in your project
I think that the problem is not about streamReader in here.
When you run the program, your program runs in a specific folder. Basically, That folder is locked by your program. In that case, when you close the program, it will be unlocked.
To fix the issue, I would suggest to write/delete/update to different folder.
Another solution could be to check file readOnly attribute and change this attribute which explained in here
Last solution could be using different users. What I mean is that, if you create a file with different user which not admin, you can delete with Admin user. However, I would definitely not go with this solution cuz it is too tricky to manage different users if you are not advance windows user.
I need to create a .txt file in C# .
Is there a way (and how to do?) to create a file and open it in Notepad, but without saving in somewhere first? The user would save it after he checks it.
No not really, i've seen some programs that do this like so, but its not ideal:
Create a temporary file, most programs use the temp directory
you get there by using %temp% or C:\Users\{username}\AppData\Local\Temp so e.g. File.Create(#"C:\Users\{username}\AppData\Local\Temp\myTempFile.Txt")
Open the file with notepad. (File.Open(#"C:\Users\{username}\AppData\Local\Temp\myTempFile.Txt"))
The user makes the change and saves
Your program checks the file to see if any edits were made.
if any edits have been made, you can prompt the user to save the file to the actual location.
e.g. !string.IsNullOrWhiteSpace(File.ReadAllText(#"C:\Users\{username}\AppData\Local\Temp\myTempFile.Txt"))
If the user wants to save the file, the file gets copied to the real location
File.Copy(#"C:\Users\{username}\AppData\Local\Temp\myTempFile.Txt", #"c:\myRealPath\MyRealFileName.txt"
I created a way (I don't know if it already exists), using System.Diagnostics and System.Reflection libraries. My code is:
File.WriteAllText($#"{Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)}\exampleDoc.txt", "information inside file");
while (!File.Exists($#"{Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)}\exampleDoc.txt")) { }
Process.Start($#"{Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)}\exampleDoc.txt");
while (Process.GetProcesses().Where(prc => { try { return prc.MainWindowTitle.Contains("exampleDoc.txt"); } catch { return false; } }).Count() == 0) { }
File.Delete($#"{Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)}\exampleDoc.txt");
the situation: Files are being dumped in a folder. This folder is being constantly monitored with own logic. When files are in the folder they are being processed automatically. We only want to process files that are fully copied into the directory.
In case we copy a large file e.g. 100MB to a folder, we don't want to process that file until it is fully copied ('complete').
Currently we test this with this code:
FileStream fs = null;
try {
fs = fileInfo.Open(FileMode.Open, FileAccess.Read, FileShare.Read);
// file is 'complete'
} catch (System.Security.SecurityException) {
// file is locked, don't do stuff (maybe Windows Explorer is still copying).
}
catch {}
finally {
fs?.Close();
}
As I think the SO User Hans Passant once said, the only way to test this is to try opening this file.
This code works but is 'old'.
Are there more efficient methods/techniques to implement and test this? (as performance is critical, the faster, the better).
The following code fails to delete the file and prints file delete: so I know the file exists. With my app open I am able to delete the file in file explorer.
How can I debug this?
1) File permissions? My app created the file so should be able to delete? Regardless it would throw an exception and hit my catch debug message.
2) The file exists! According to the docs any other failure besides non-existence should be caught in my catch...
if (File.Exists(fn))
{
Debug.WriteLine("file delete: " + fn);
try
{
File.Delete(fn);
}
catch
{
Debug.WriteLine("Could not delete: " + fn);
}
} else {
Debug.WriteLine("File doesn't exist: "+fn);
}
The file is saved from a RichTextBox using the following code if this matters.
TextRange range;
FileStream fStream;
range = new TextRange(mNotepad.Document.ContentStart, mNotepad.Document.ContentEnd);
fStream = new FileStream(fn, FileMode.Create);
range.Save(fStream, DataFormats.XamlPackage);
fStream.Close();
Deleting a file does not provide a guarantee that the file will actually be removed from the file system. The file might have been opened by another process, which explicitly specified delete sharing. Very similar to read and write sharing. Also available in .NET, you'd pass FileShare.Delete to the FileStream constructor.
But the physical file can of course not be removed until all processes close the file. So it lingers beyond the File.Delete() call, can be seen by File.Exists() as well. Opening the file can no longer work, that will be rejected with access denied. Otherwise an excellent reason to never use File.Exists(), it has many problems.
If you want to find out what other process has the file opened then you can use a utility like SysInternals' Handle or Process Explorer. Expect to find back a program like a virus scanner or search indexer, could be anything however. Like a .NET program :)
From MSDN:
If the file to be deleted does not exist, no exception is thrown.
Make sure your path exists. I know you said you did, but check again.
Make sure you reach the actual File.Delete line
Cheers
I had the same issue before, follow the steps to see if it helps you. As silly as it may sound. Make sure no processes other than yours are making use of that file you created? Is this application multi-threaded? Do you have services running that use the file?
Make sure your not in debug mode, and do a Build - Clean
Check that the file is still at the location and copy the file path.
Put a break point right before file deletion.
Rebuild your project after you put your break-point.
Press F5 to debug and step through the code.
Check that the file path matches the one that you have.
I tried to reproduce similar situation with my own code
string fn = #"C:\Users\Public\Pictures\Sample Pictures\Desert - Copy.jpg";
//The file is locked by Image.FromFile
Image img = Image.FromFile(fn);
//If img.Dispose() here, then file is unlocked and can be deleted
if (File.Exists(fn))
{
try
{
File.Delete(fn);
Debug.WriteLine("file delete: " + fn);
}
catch
{
//Caught
Debug.WriteLine("Could not delete: " + fn);
}
}
else
{
Debug.WriteLine("File doesn't exist: " + fn);
}
I found the file is locked by Image.FromFile() and therefore Could not delete.
For the same reason, I believe your file with path fn is locked by the Filestream ftream
Can you try to do
fStream.Dispose();
before your delete process and rerun the program to see if you can delete the file? thanks. You can dispose the fstream and create a new one if needed,right?
I am trying a simple move as shown below and get the following error: "The process cannot access the file because it is being used by another process." How do I fix this? Thanks.
FileInfo file1 = new FileInfo(srcFile);
if (file1.Exists)
{
FileInfo file2 = new FileInfo(destFile);
if (!file2.Exists)
{
try
{
File.Move(srcFile, destFile);
}
catch (System.IO.IOException e)
{
Console.WriteLine(e.Message);
}
}
}
The error means that the file is in use:
either by your application (you need to close the file in order to be able to move it)
or by another application. There isn't much you can do here, but retry later.
Are you creating or opening file1 from within your code? If so, you'll need to close the FileStream before attempting the move.
Check with process explorer which process holds the file open.
Use procmon to find out which process is using the file and handle the situation.
When you catch this exception, you can try calling the Windows API MoveFileEx, with the MOVEFILE_DELAY_UNTIL_REBOOT flag. This will move the file the next time you reboot; this is want installers normally do when they detect a locked file. You need to be admin or LocalSystem for this to work.
Use Unlocker to see file locks. It will help you to figure out the problem.
http://www.emptyloop.com/unlocker/
maybe open the file1 in your code before you move it and don't close the filestream