BinaryReader throws NullReferenceException when being disposed - c#

I have a class MyClass that needs data from a file that will be used throughout the run of the program. To read in the data I have another class OpenFileService that derives from IDisposable and uses a BinaryReader to read in all the data:
internal class OpenFileService : IDisposable
{
#region disposing data
bool disposed = false;
public void Dispose()
{
if (!disposed)
{
Dispose(true);
GC.SuppressFinalize(this);
disposed = true;
}
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
br.Dispose();
}
}
~OpenFileService()
{
Dispose(false);
}
#endregion
internal event EventHandler ErrorInFileReadEventHandler;
internal event EventHandler SuccessfulFileReadEventHandler;
private BinaryReader br;
internal void OpenFile(object obj)
{
MyClass sender = obj as MyClass;
bool isWrongFormat = false;
try
{
br = new BinaryReader(File.Open((sender).fileName, FileMode.Open));
//read in header from file.
if (//header shows wrong file format)
{
isWrongFormat = true;
throw new System.Exception();
}
//read rest of file.
SuccessfulFileReadEventHandler(this,null);
}
catch
{
if (isWrongFormat)
MessageBox.Show("Wrong format.");
else
MessageBox.Show("Couldn't access.");
ErrorInFileReadEventHandler(this, null);
return;
}
finally
{
this.Dispose();
}
}
}
And it is used as such:
class MyClass
{
internal filePath; //assuming it has already been determined
internal ImageData(string filePath)
{
this.filePath = filePath;
OpenFileService ofs = new OpenFileService();
ofs.ErrorInFileReadEventHandler += new EventHandler(UnsuccessfulFileRead);
ofs.SuccessfulFileReadEventHandler += new EventHandler(SuccessfulFileRead);
Thread thread = new Thread(new ParameterizedThreadStart(ofs.OpenFile));
thread.IsBackground = true;
thread.Start(this);
}
}
Now when the file format is wrong and I create the exception myself in the try block, everything works without any problems, but when the file could actually not be accessed (e.g. write-protected) br.Dispose(); creates a NullReferenceException and I cannot figure out why.
I really stripped down the code to its bare essentials, I hope it's not too long.
Edit: Possible answer can be found from the accepted answer here as a recommended answer by Microsoft.

The issue might become clearer if you split your file-open logic across two lines:
try
{
var fs = File.Open((sender).fileName, FileMode.Open);
br = new BinaryReader(fs);
}
finally
{
br.Dispose();
}
When the File.Open call fails, the exception is thrown without anything being assigned to the br field. When you attempt to dispose it in the finally block, it would still be null, thus your exception.
Edit: The way I would suggest fixing this:
try
{
using (FileStream fs = File.Open(sender.fileName, FileMode.Open))
using (BinaryReader br = new BinaryReader(fs))
{
//read in header from file.
if ( /*header shows wrong file format*/ )
{
isWrongFormat = true;
MessageBox.Show("Wrong format.");
ErrorInFileReadEventHandler(this, null);
}
else
{
//read rest of file.
SuccessfulFileReadEventHandler(this, null);
}
}
}
catch
{
MessageBox.Show("Couldn't access.");
ErrorInFileReadEventHandler(this, null);
}
In the process, I've demoted your BinaryReader from a field to a local variable. Since you're only accessing it within the OpenFile method (and disposing it before returning), there's no need for its reference to persist outside the method.

Related

How to Efficiently Read From a Pipe Stream when using IPC C#

I wrote the simplified version of my program below. Process A launches a child process (Process B). I use an anonymous pipe to write information about the progress of a method running on process B. Meanwhile I have a function in process A that continually reads from a stream to see if there is a new update coming in from the pipe. If there is, the form on process A is updated to reflect the progress. This works as expected, however I am wondering if there is a better way to accomplish this without having to continually check the stream to see if there are any new updates to the progress.
/////////////////
///Process A ////
/////////////////
public void LaunchProcessB()
{
using (AnonymousPipeServerStream pipeServer = new AnonymousPipeServerStream(PipeDirection.In,
HandleInheritability.Inheritable))
{
var _Process = new Process();
_Process.StartInfo.FileName = exeString;
_Process.StartInfo.Arguments = pipeServer.GetClientHandleAsString()
_Process.StartInfo.RedirectStandardOutput = true;
_Process.StartInfo.RedirectStandardInput = true;
_Process.StartInfo.CreateNoWindow = true;
_Process.StartInfo.UseShellExecute = false;
_Process.Start(); //launches process B
pipeServer.DisposeLocalCopyOfClientHandle();
using (StreamReader sr = new StreamReader(pipeServer))
{
try
{
while (true)
{
string temp = sr.ReadLine();
if (temp == null) break;
int result;
if (Int32.TryParse(temp, out result))
ShowDocumentProgress(result);
else ShowProgress(temp);
}
}
catch (Exception)
{
//error occured when reading from stream.
}
}
if (!_Process.Responding && !_Process.HasExited)
{
_Process.Kill();
return;
}
_Process.WaitForExit(10000);
}
}
private void ShowProgressPercent(int percentage)
{
if (percentage > currentPercentage)
{
progressBar.Value = percentage;
}
}
private void ShowProgress(string progressString)
{
labelMessage.Text = progressString;
}
/////////////////
///Process B ////
/////////////////
private StreamWriter _progressWriter;
private PipeStream _progressPipe;
static int Main(string[] args)
{
using (progressPipe = new AnonymousPipeClientStream(PipeDirection.Out, args[0]))
using (_progressWriter = new StreamWriter(_progressPipe))
{
RunLongProcess()
}
}
private void RunLongProcess()
{
//attaches events to PercentProgress and StageProgress methods.
}
private void PercentProgress(int percentage)
{
_progressWriter.WriteLine(percentage.ToString());
_progressPipe.WaitForPipeDrain();
}
private void StageProgress(string stage)
{
_progressWriter.WriteLine(stage);
_progressPipe.WaitForPipeDrain();
}
The while condition is not necessary. Simply read until temp is null. That's the end signal of the stream.
Make this a while(true) loop.
I think you also need to add exception handling to catch the process terminating and severing the pipe. !_Process.HasExited && pipeServer.IsConnected is not enough because it might be true but immediately switch to false after the test.
I also would add a WaitForExit at the end to make sure the system is quiesced before you continue.

File locking technique in thread synchronization scenario is failing

I was trying to write a class which let me do read and write operation on multiple files (like 5-10) while locking them from any kind of access. Everytime I access a file (doesn't matter if for read or write) a new file with the same name and a different extension is created, so other threads (belonging to different applications) are notified of the lock (ex. message.msg -> lock file message.lock created).
Every instance of the application will write in it's own file and read in all other applications files (including its).
Unfortunately, when I start several instances (like 3-4) of the application which uses this class, even if at first they look like they're working, then in a matter or seconds / maybe a couple of minutes it looks like one thread fails to release a file. This of course blocks the other threads too which are unable to read that specific file.
I say this because when everything app freezes I can see a permanent .lock file.
Of course I could put a Lock expire time (which probably would work in this scenario), but why is this happening?
To me this code looks reasonable, but of course I'm still a newbie...so...is there any mayor flaw in my ratio?
(Don't be scared by the length of this, they're only 2 functions and they do pretty much the same thing, except than for the central part)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading;
namespace y3kMessenger
{
static class FileLockAccess
{
public static string[] readAllLines(string path)
{
bool isLocked = false;
string[] toReturn;
string lockPath = path.Replace(Global.msgExtension, Global.lockExtension);
StreamWriter w;
//locking ...
while (!isLocked)
{
if (!File.Exists(lockPath))
{
try
{
using (w = new StreamWriter(lockPath))
{
w.WriteLine(" ");
}
isLocked = true;
}
catch (Exception e) { }
}
Thread.Sleep(10);
}
//locked, proceed with read
toReturn = File.ReadAllLines(path);
//release the lock
while (isLocked)
{
try
{
File.Delete(lockPath);
}
catch (Exception e) { }
isLocked = false;
}
return toReturn;
}
public static void writeLine(string path, string text, bool append)
{
bool isLocked = false;
string lockPath = path.Replace(Global.msgExtension, Global.lockExtension);
StreamWriter w;
//locking ...
while (!isLocked)
{
if (!File.Exists(lockPath))
{
try
{
using (w = new StreamWriter(lockPath))
{
w.WriteLine(" ");
}
isLocked = true;
}
catch (Exception e) { }
}
Thread.Sleep(10);
}
//locked, proceed with write
using (w = new StreamWriter(path, append))
w.WriteLine(text);
//release the lock
while (isLocked)
{
try
{
File.Delete(lockPath);
}
catch (Exception e) { }
isLocked = false;
}
}
}
}
EDIT: as an add to the discussion, the following code seems to work:
public static string[] readAllLines(string path)
{
bool done = false;
string[] toReturn = null;
while (!done)
{
try
{
toReturn = File.ReadAllLines(path);
done = true;
}
catch (Exception e)
{
Thread.Sleep(50);
}
}
return toReturn;
}
public static void writeLine(string path, string text, bool append)
{
bool done = false;
while (!done)
{
try
{
using (StreamWriter w = File.AppendText(path))
{
w.WriteLine(text);
}
done = true;
}
catch (Exception e)
{
Thread.Sleep(50);
}
}
}
So the problem shouldn't reside in what threads are doing (I haven't changed anything else since the interface exposed by these methods is the same as the first 2)

C# Networking Issue Multiple Processes

Whenever my client loses connection of the server, I have a re-connection loop which continuously looks for the server.
As this loop runs, it generates a process of conhost.exe and csc.exe every time it tries to connect until the computer slows to a halt.
Does anyone know what would create these processes?
So what happens, is anytime there is a failconnection or a loseconnection, I call Initialize. This should properly dispose all components and then reinitialize them all.
Initialize Method for NetworkInterface and TcpInterface:
public void Initialize()
{
if (ni != null)
{
ni.Dispose();
GC.Collect();
}
if (tcpInterface != null)
{
tcpInterface.Dispose();
}
tcpInterface = new TcpInterface();
if (!string.IsNullOrEmpty(ipAddress))
{
tcpInterface.Settings = new TcpSettings
{
RemoteIp = ipAddress,
Port = _port,
PacketDenotesLength = false
};
}
tcpInterface.NewConnection += new TcpInterface.TcpNetworkStateEventHandler(tcpInterface_NewConnection);
tcpInterface.FailConnection += new TcpInterface.ConnectionEventHandler(tcpInterface_FailConnection);
tcpInterface.ReceivePacket += new TcpInterface.TcpInterfacePacketEventHandler(tcpInterface_ReceivePacket);
tcpInterface.LoseConnection += new TcpInterface.TcpNetworkStateEventHandler(tcpInterface_LoseConnection);
ni = new NetworkInterface<string, PacketInfo>();
ni.Services.Register("TcpInterface", tcpInterface);
ni.Initialize();
}
Dipose for TcpInterface:
public void Dispose()
{
if (TcpClient != null)// && TcpClient.Connected)
{
if (TcpClient.Connected)
{
NetworkStream stream = TcpClient.GetStream();
if (stream != null)
{
stream.Close();
}
}
TcpClient.Close();
TcpClient = null;
}
Buffer = null;
BufferBuilder = null;
}
Dispose for ni:
public void Dispose()
{
Services.Dispose();
}
csc.exe is C# compiler.
do you use XmlSerializer for serlization/deserialization? if you didn't sgen'ed your assemblies, then XmlSerializer will start csc.exe and compile some code to temporary folder.
Another option, is using CodeDom in C#. the code then will compile using csc.exe.

C# IOException: The process cannot access the file because it is being used by another process

I have a slight problem. What my application is supose to do, is to watch a folder for any newly copied file with the extention '.XSD' open the file and assign the lines to an array. After that the data from the array should be inserted into a MySQL database, then move the used file to another folder if it's done.
The problem is that the application works fine with the first file, but as soon as the next file is copied to the folder I get this exception for example: 'The process cannot access the file 'C:\inetpub\admission\file2.XPD' because it is being used by another process'.
If two files on the onther hand is copied at the same time there's no problem at all.
The following code is on the main window:
public partial class Form1 : Form
{
static string folder = specified path;
static FileProcessor processor;
public Form1()
{
InitializeComponent();
processor = new FileProcessor();
InitializeWatcher();
}
static FileSystemWatcher watcher;
static void InitializeWatcher()
{
watcher = new FileSystemWatcher();
watcher.Path = folder;
watcher.Created += new FileSystemEventHandler(watcher_Created);
watcher.EnableRaisingEvents = true;
watcher.Filter = "*.XPD";
}
static void watcher_Created(object sender, FileSystemEventArgs e)
{
processor.QueueInput(e.FullPath);
}
}
As you can see the file's path is entered into a queue for processing which is on another class called FileProcessor:
class FileProcessor
{
private Queue<string> workQueue;
private Thread workerThread;
private EventWaitHandle waitHandle;
public FileProcessor()
{
workQueue = new Queue<string>();
waitHandle = new AutoResetEvent(true);
}
public void QueueInput(string filepath)
{
workQueue.Enqueue(filepath);
if (workerThread == null)
{
workerThread = new Thread(new ThreadStart(Work));
workerThread.Start();
}
else if (workerThread.ThreadState == ThreadState.WaitSleepJoin)
{
waitHandle.Set();
}
}
private void Work()
{
while (true)
{
string filepath = RetrieveFile();
if (filepath != null)
ProcessFile(filepath);
else
waitHandle.WaitOne();
}
}
private string RetrieveFile()
{
if (workQueue.Count > 0)
return workQueue.Dequeue();
else
return null;
}
private void ProcessFile(string filepath)
{
string xName = Path.GetFileName(filepath);
string fName = Path.GetFileNameWithoutExtension(filepath);
string gfolder = specified path;
bool fileInUse = true;
string line;
string[] itemArray = null;
int i = 0;
#region Declare Db variables
//variables for each field of the database is created here
#endregion
#region Populate array
while (fileInUse == true)
{
FileStream fs = new FileStream(filepath, FileMode.Open, FileAccess.Read,
FileShare.ReadWrite);
StreamReader reader = new StreamReader(fs);
itemArray = new string[75];
while (!reader.EndOfStream == true)
{
line = reader.ReadLine();
itemArray[i] = line;
i++;
}
fs.Flush();
reader.Close();
reader.Dispose();
i = 0;
fileInUse = false;
}
#endregion
#region Assign Db variables
//here all the variables get there values from the array
#endregion
#region MySql Connection
//here the connection to mysql is made and the variables are inserted into the db
#endregion
#region Test and Move file
if (System.IO.File.Exists(gfolder + xName))
{
System.IO.File.Delete(gfolder + xName);
}
Directory.Move(filepath, gfolder + xName);
#endregion
}
}
The problem I get occurs in the Populate array region. I read alot of other threads and was lead to believe that by flushing the file stream would help...
I am also thinking of adding a try..catch for if the file process was successful, the file is moved to gfolder and if it failed, moved to bfolder
Any help would be awesome
Tx
You're not disposing of your FileStream instance, so a lock remains on the file. Change your code to use using blocks:
using (var fileStream = new FileStream(...))
{
using (var reader = new StreamReader(fileStream))
{
}
}
These using blocks will ensure the instances are correctly disposed of.
Also, why are you calling Flush on the file stream? You're not writing anything with it...
I would suggest :
1° use the using syntax on StreamReader
2° use the using syntax on FileStream

c# How to access file if that file is processed by other process?

public static void WriteLine(string text)
{
StreamWriter log;
if (!File.Exists(Filename))
{
log = new StreamWriter(Filename);
}
else
{
log = File.AppendText(Filename);
}
while this method is processed, other process also call this method. There will be error occur "file has been acess by other process". How to solve this problem by waiting the previous process finish.
I think the op wants to wait until the filehandle is free to use and then write to the file. In this case you should try to get the filehandle, catch the exception and if the exception is because the file is accessed by another process then wait a short time and try again.
public static void WriteLine(string text)
{
bool success = false;
while (!success)
{
try
{
using (var fs = new FileStream(Filename, FileMode.Append))
{
// todo: write to stream here
success = true;
}
}
catch (IOException)
{
int errno = Marshal.GetLastWin32Error();
if(errno != 32) // ERROR_SHARING_VIOLATION
{
// we only want to handle the
// "The process cannot access the file because it is being used by another process"
// exception and try again, all other exceptions should not be caught here
throw;
}
Thread.Sleep(100);
}
}
}
Both processes need to create a FileStream where they specify a FileShare mode of Write. You can then also drop the test whether the file exists, and just use the Append FileMode.

Categories