Best way to implement a file access check in a loop - c#

I'm trying to find a better way to check for file access in a loop.
Here's my code:
while (true)
{
try
{
using (FileStream Fs = new FileStream(fileName, FileMode.Open, FileAccess.Write))
using (StreamReader stream = new StreamReader(Fs))
{
break;
}
}
catch (FileNotFoundException)
{
break;
}
catch (ArgumentException)
{
break;
}
catch (IOException)
{
Thread.Sleep(1000);
}
}
Here's what I've tried so far, but it does not work has exprected:
FileIOPermission writePermission = new FileIOPermission(FileIOPermissionAccess.Write, fileName);
while (true)
{
try
{
writePermission.Demand();
break;
}
catch (SecurityException e)
{
Thread.Sleep(1000);
}
}
AND
while (true)
{
if (SecurityManager.IsGranted(writePermission))
break;
Thread.Sleep(1000);
}

I wrote this the other day.
public static void Retry(Action fileAction, int iteration)
{
try
{
fileAction.Invoke();
}
catch (IOException)
{
if (interation < MaxRetries)
{
System.Threading.Thread.Sleep(IterationThrottleMS);
Retry(fileAction, ++iteration);
}
else
{
throw;
}
}
}
You would have to declare MaxRetries and IterationThrottleMS yourself, or perhaps make them parameters.
EDIT I include an example. As I admit, this would be over engineering unless it were resused
//A little prep
const int IterationThrottleMS = 1000;
const int MaxRetries = 5;
public static void Retry(Action fileAction)
{
Retry(fileAction, 1)
}
...
// Your first example
try
{
Retry(() => {
using (FileStream Fs = new FileStream(
fileName,
FileMode.Open,
FileAccess.Write)
StreamReader stream = new StreamReader(Fs);
});
}
catch (FileNotFoundException) {/*Somthing Sensible*/}
catch (ArgumentException) {/*Somthing Sensible*/}
catch (IOException) {/*Somthing Sensible*/}
...
// Your second example
try
{
Retry(() => writePermission.Demand());
}
catch (FileNotFoundException) {/*Somthing Sensible*/}
catch (ArgumentException) {/*Somthing Sensible*/}
catch (IOException) {/*Somthing Sensible*/}

Related

Process cannot access file because its used by another process

So I'm getting exception "Process cannot access file because its used by another process.
The exception will show when i call this particular method:
public async static Task<bool> DownloadFileFromFTP(string PathToFile, string AppName)
{
return await Task.Run(() => {
if (File.Exists("settings.xml"))
{
XmlSerializer xs = new XmlSerializer(typeof(Information));
FileStream read = new FileStream("settings.xml", FileMode.Open, FileAccess.Read, FileShare.Read);
Information info = (Information)xs.Deserialize(read);
try
{
FtpClient client = new FtpClient(info.HDSynologyIP);
string a = info.FtpPassword;
string FTPPassword = EncryDecryptor.Decrypt(a);
client.Credentials = new NetworkCredential(info.FtpUsername, FTPPassword);
client.Connect();
bool finish = client.DownloadFile(#info.Downloads + "\\" + AppName, PathToFile, FtpLocalExists.Overwrite, FluentFTP.FtpVerify.Retry);
if (finish == true)
{
client.Disconnect();
read.Close();
return true;
}
else
{
client.Disconnect();
read.Close();
return false;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
read.Close();
}
read.Close();
}
else
{
MessageBox.Show("Missing settings.xml file");
return false;
}
return false;
});
}
And call it in another class like this:
await General_Functions.DownloadFileFromFTP("Ultra_Script/Basic_SW/Adobe_Reader.exe", "Adobe_Reader.exe");
It wasn't asynchronous before but i had to remake it into asynchronous method. But i think I'm closing reader and client correctly. Can it be problem of async method? Because i don't had this problem before i made it asynchronous.
Can someone explain what I'm doing wrong?
Note, I am using FluentFTP from https://github.com/robinrodricks/FluentFTP .
use using to terminate the file reader process
using(FileStream read = new FileStream("settings.xml", FileMode.Open, FileAccess.Read, FileShare.Read))
{
// your code here.....
}

How can be setted Console.SetOut(TextWriter) with multi thread C#?

Assuming I have a multi thread ForEach I would like that every cycle have the Console.WriteLine() converted into a file, the example I have found for mono thread is something like:
FileStream ostrm;
StreamWriter writer;
TextWriter oldOut = Console.Out;
try
{
ostrm = new FileStream("C:\\Users\\Public\\Documents/Redirect.txt", FileMode.OpenOrCreate, FileAccess.Write);
writer = new StreamWriter(ostrm);
}
catch (Exception e)
{
Console.WriteLine("Cannot open Redirect.txt for writing");
Console.WriteLine(e.Message);
return;
}
Console.SetOut(writer);
Now for multi thread I have try something like:
IList<String> testCaseList = ExcelDataAccess.GetTestCases();
Parallel.ForEach(testCaseList, new ParallelOptions { MaxDegreeOfParallelism = 1 }, currentTestCase =>`
{
FileStream ostrm;
StreamWriter writer;
TextWriter oldOut = Console.Out;
try
{
ostrm = new FileStream("C:\\Users\\Public\\Documents/Redirect" + currentTestCase +".txt", FileMode.OpenOrCreate, FileAccess.Write);
writer = new StreamWriter(ostrm);
}
catch (Exception e)
{
Console.WriteLine("Cannot open Redirect.txt for writing");
Console.WriteLine(e.Message);
return;
}
Console.SetOut(writer);
Console.WriteLine("Running test: " + currentTestCase);
//Do some other stuff and some Console.WriteLine();
}
But in this way inside every file what is written is not what expected and multi thread looks not handled correctly. How to solve this?

file in use by another process ... while i can copy

I get a "file in use by another process exception" when creating a email and wants to add this file as attachment.
When i try to copy the same file to an other directory there is no problem. (state of the file is still the same)
does anybody knows whats happening here? and how i can solve this?
here is the code:
public Boolean AddAttachment(string filePath, string newName = "")
{
try
{
MimeData mime = _message.AddAttachment(filePath);
if (!string.IsNullOrEmpty(newName))
{
mime.FileName = newName;
}
return true;
}
catch (Exception err)
{
if (! AddAttachmentIfInUse(filePath, newName))
{
AddErrorInfo(err.Message, "AddAttachment", err.Source);
return false;
}
else
{
return true;
}
}
}
private Boolean AddAttachmentIfInUse(string filePath, string newName = "")
{
byte[] data;
string contentType = "";
string fileName = Path.GetFileName(filePath);
try
{
using (FileStream stream = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
data = new byte[stream.Length];
stream.Read(data, 0, (int)stream.Length);
}
// data = File.ReadAllBytes(filePath);
MimeData mime = new MimeFactory().CreateMimeData();
mime.Data = data;
mime.ContentType = ContentType.Parse(contentType);
if (!string.IsNullOrEmpty(newName))
{
mime.FileName = newName;
}
else{
mime.FileName = fileName;
}
return true;
}
catch (Exception err)
{
AddErrorInfo(err.Message, "AddAttachmentIfInUse", err.Source);
return false;
}
}
thanks
The 1st function gets the the error in _message.AddAttachment(..) ...
I had to change the 2nd function: do not use File.Open() but use FileStream() and now it's working well.
using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)){
data = new byte[fs.Length];
fs.Read(data, 0, (int)fs.Length);
}

StreamWriter object doesn't work at all

This code works fine within SaveFileDialog
private void buttonSaveAs_Click(object sender, EventArgs e)
{
try
{
if (selectedFileInfo != null)
{
// Save File
SaveFileDialog saveFileDialog1 = new SaveFileDialog();
saveFileDialog1.InitialDirectory = explorerTree2.SelectedPath;
// set a default file name
saveFileDialog1.FileName = Path.GetFileNameWithoutExtension(selectedFileInfo.Name) + "-COPY" + selectedFileInfo.Extension;
// set filters - this can be done in properties as well
saveFileDialog1.Filter = "HTM files (*.htm)|*.htm|HTML files (*.html)|*.html|XML files (*.xml)|*.xml|Text files (*.txt)|*.txt|All files (*.*)|*.*";
#region Define filter index
if (selectedFileInfo.Extension.Equals(".htm")) // HTM files (*.htm)|*.htm
{
saveFileDialog1.FilterIndex = 1;
}
else // All files (*.*)|*.*
{
saveFileDialog1.FilterIndex = 5;
}
#endregion
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
using (StreamWriter sw = new StreamWriter(saveFileDialog1.FileName))
{
sw.Write(scintilla1.Text);
sw.Flush();
sw.Close();
}
}
}
}
catch (IOException ex)
{
MessageBox.Show(ex.Message);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
And another does not. And there NO is any error as well. Any clue?
private void buttonSave_Click(object sender, EventArgs e)
{
try
{
if (selectedFileInfo != null)
{
using (FileStream fs = new FileStream(selectedFileInfo.Name, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
StreamWriter sw = new StreamWriter(fs);
sw.AutoFlush = true;
sw.Write(scintilla1.Text);
sw.Flush();
sw.Close();
}
}
}
catch (IOException ex)
{
MessageBox.Show(ex.Message);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
P.S. This option does not work as well
using (FileStream fs = new FileStream(selectedFileInfo.Name, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
using (StreamWriter sw = new StreamWriter(fs))
{
sw.AutoFlush = true;
sw.Write(scintilla1.Text);
sw.Flush();
sw.Close();
}
}
I found correct solution
where scintilla1.Text is string you have to write
and selectedFileInfo is a FileInfo object. In your case scintilla1.Text might be like a string or RichTextBox or any other text editor control.
private void buttonSave_Click(object sender, EventArgs e)
{
if (selectedFileInfo != null)
{
FileStream stream = null;
try
{
stream = selectedFileInfo.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None);
using (StreamWriter sw = new StreamWriter(stream))
{
sw.AutoFlush = true;
sw.Write(scintilla1.Text);
sw.Flush();
sw.Close();
}
}
catch (IOException ex)
{
MessageBox.Show(ex.Message);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
if (stream != null)
stream.Close();
}
}
}

FileStream and ObjectDisposedException in .NET CF

public byte[] GetFile(string filename)
{
FileStream aStream = File.Open(filename, FileMode.Open, FileAccess.Read);
BinaryReader binReader = new BinaryReader(aStream);
binReader.BaseStream.Position = 0;
byte[] binFile = binReader.ReadBytes(Convert.ToInt32(binReader.BaseStream.Length));
binReader.Close();
return binFile;
}
I run this method for a number of filepaths, problem is whenever a file cannot be accessed with File.Open (because it is used by another process) I get:
'aStream.Position' threw an exception of type 'System.ObjectDisposedException'
on the following line:
binReader.BaseStream.Position = 0;
And seldom I get
{System.IO.IOException: The process can not access the file '\folder\file.txt' because it is being used by another process.}
This is the exception I want. So why is the object disposed most of the times?
Note: I first had the FileStream line in a using statement but removed it because I thought that might have disposed the object. But the problem remains.
Edit: Using Compact Framework, which doesn't have ReadAllBytes.
Maybe that part of the time your FileStream is throwing the IOException whenever your file is in use, and at other times, perhaps, you are getting the ObjectDisposedException because your array is not initialized.
Obviously, I can not test this theory.
See if you can copy-n-paste this one with good results:
public byte[] GetFile(string filename)
{
byte[] binFile = null;
try
{
using (var aStream = File.Open(filename, FileMode.Open, FileAccess.Read))
{
BinaryReader binReader = new BinaryReader(aStream);
binFile = new byte[binReader.BaseStream.Length];
binReader.BaseStream.Position = 0; // <= this step should not be necessary
binFile = binReader.ReadBytes(binReader.BaseStream.Length);
binReader.Close();
}
} catch (IOException err) {
// file is being used by another process.
} catch (ObjectDisposedException err) {
// I am guessing you would never see this because your binFile is not disposed
}
return binFile;
}
Be sure to check for null return variables!
EDIT:
I wrote (what I think is) a simpler version. I tested it, and it seems to work OK. I also prefer Read() overload to ReadBytes(), because I know how much data was pulled in.
First, is the test function that calls the method for every image in my Pictures folder:
public void Test() {
DirectoryInfo dir = new DirectoryInfo(Environment.GetFolderPath(Environment.SpecialFolder.Personal));
foreach (var subDir in dir.GetDirectories()) {
if (-1 < subDir.Name.ToLower().IndexOf("pictures")) {
foreach (var file in subDir.GetFiles()) {
byte[] data = GetFile(file.FullName);
if (data != null) {
Console.WriteLine(data.Length);
}
}
}
}
}
public byte[] GetFile(string filename) {
byte[] result = null;
try {
if (File.Exists(filename)) {
int len = 0;
FileInfo file = new FileInfo(filename);
byte[] data = new byte[file.Length];
using (BinaryReader br = new BinaryReader(file.Open(FileMode.Open, FileAccess.Read))) {
len = br.Read(data, 0, data.Length);
br.Close();
}
if (0 < len) {
if (len == data.Length) {
return data;
} else {
// this section of code was never triggered in my tests;
// however, it is good to keep it as a backup.
byte[] dat2 = new byte[len];
Array.Copy(data, dat2, len);
return dat2;
}
}
}
} catch (IOException err) {
// file is being used by another process.
} catch (ObjectDisposedException err) {
// I am guessing you would never see this because your binFile is not disposed
}
return result;
}
I don't see any reason why these would not work - unless you are having an int overflow.
Just use this:
byte[] contents = File.ReadAllBytes(filename);
Why don't you simply use
public byte[] GetFile(string filename)
{
try { return File.ReadAllBytes(filename); }
catch { return null; }
}
Just for fun, you could even define an extension method
public static class Extensions
{
public static byte[] GetFile(this string filename)
{
try { return File.ReadAllBytes(filename); }
catch { return null; }
}
}
so you could do byte[] myfile = filename.GetFile();.
Remember you must check that return is not null before proceed:
if (myfile != null)
{
// Do what you need
}

Categories