I'm getting the following run time error: "I/O error while writing the file: "The process cannot access the file bin\Debug/test.txt because it is being used by another process."
I have closed the files in all cases it's being written, except the case when File.ReadAllText(path) is used as my understanding is that the filestream is closed automatically. How do I correct this error?
Here is the relevant code:
StreamReader sr = null;
sr = new StreamReader(new FileStream(path, FileMode.Open, FileAccess.Read));
try
{
// Open the file for reading; assumes file exists
sr = new StreamReader(new FileStream(path, FileMode.Open, FileAccess.Read));
while (!sr.EndOfStream)
{
line = sr.ReadLine();
fields = line.Split(',');
aniNameCol1[count] = fields[0];
aniNameCol2[count] = fields[1];
aniNameCol3[count] = fields[2];
aniNameCol4[count] = fields[3];
count++;
}
sr.Close();
sr.Dispose();
}
catch (FileNotFoundException)
{
MessageBox.Show("File Not Found" + path);
}
catch (Exception ex)
{
MessageBox.Show("Error while reading the file: " + ex.GetType().ToString() + ": " + ex.Message);
}
finally
{
if (sr != null)
{
sr.Close();
sr.Dispose();
}
}
try
{
string input = File.ReadAllText(path);
int i = 0;
int j = 0;
foreach (var row in input.Split('\n'))
{
j = 0;
foreach (var col in row.Trim().Split(','))
{
twoDArray[i, j] = col.Trim().ToString();
j++;
}
i++;
}
}
catch (FileNotFoundException)
{
MessageBox.Show("File Not Found" + path);
}
catch (Exception ex)
{
MessageBox.Show("Error while reading the file: " + ex.GetType().ToString() + ": " + ex.Message);
}
In another method, text is written in the file:
StreamWriter sw = null;
try
{
// open the same file for writing
sw = new StreamWriter(new FileStream(path, FileMode.Create, FileAccess.Write));
for(int i = 0; i < rowMax; i++)
{
for(int j = 0; j < colMax; j++)
{
sw.WriteLine(twoDArray[i, j].ToString() + ", ");
}
}
sw.Close();
sw.Dispose();
}
catch (IOException ex)
{
MessageBox.Show("I/O error while writing the file: " + ex.Message);
}
catch (Exception ex)
{
MessageBox.Show("Unanticipated error occurred while writing: " + ex.GetType() + "; " + ex.Message);
}
finally
{
if (sw != null)
{
sw.Close();
sw.Dispose();
}
}
Your first few lines:
StreamReader sr = null;
// opened the first time
sr = new StreamReader(new FileStream(path, FileMode.Open, FileAccess.Read));
try
{
// opened it a second time
sr = new StreamReader(new FileStream(path, FileMode.Open, FileAccess.Read));
Your operatingsystem has 2 shared read accesses on the file - you are only closing/disposing one of them.
Switch to
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read))
{
using (var sr = new StreamReader(fs))
{
// do your stuff here, no need to close or flush - it is autoclosed
// when leaving the block. Do the same for writing.
}
}
It is far more robust, especially if Exceptions happen as it will be closed no matter what.
Read more about using( ... ) in this post: What are the uses of "using" in C#
Edit: stacked usings for FileStream and StreamReader
In your second code block, suspect your code is failing to invoke sw.Dispose() and here is why:
From the .NET source code
public override void Close() {
Dispose(true);
GC.SuppressFinalize(this);
}
So when you call .Close(), the framework is going to call Dispose(true). Therefore, when you explicitly write sw.Dispose(), you're trying to dispose of a StreamWriter that has already been disposed.
Remove sw.Dispose()
Related
I have a service running on a server that zip files and I notice that each day the memory consumed increases, when I deployed it on the server it was consuming 3.6Mb, today, 3 months later it was consuming 180Mb.
This is part of the code that I'm using:
for (i = 0; i < files.Count; i++)
{
try
{
if (File.Exists(#dir + zipToUpdate) && new FileInfo(#dir + zipToUpdate).Length < 104857600)
{
using (FileStream zipToOpen = new FileStream(#dir + zipToUpdate, FileMode.Open))
{
using (ZipArchive archive = new ZipArchive(zipToOpen, ZipArchiveMode.Update, false))
{
if (File.GetCreationTime(#dir + files.ElementAt(i)).AddHours(FileAge) < DateTime.Now)
{
ZipArchiveEntry fileEntry = archive.CreateEntry(files.ElementAt(i));
using (BinaryWriter writer = new BinaryWriter(fileEntry.Open()))
{
using (FileStream sr = new FileStream(#dir + files.ElementAt(i), FileMode.Open, FileAccess.Read))
{
byte[] block = new byte[32768];
int bytesRead = 0;
while ((bytesRead = sr.Read(block, 0, block.Length)) > 0)
{
writer.Write(block, 0, bytesRead);
block = new byte[32768];
}
}
}
File.Delete(#dir + files.ElementAt(i));
}
}
}
}
else
{
createZip(files.GetRange(i, files.Count-i), dir + "\\", getZipName(dir, zipToUpdate));
return;
}
}
catch (Exception ex)
{
rootlog.Error(string.Format("Erro Run - updateZip: {0}", ex.Message));
}
}
The creation of the zip or the update are similar so there is no point in paste both codes.
I do a recursive call of this for the folders inside and the service runs once each hour.
So, my question is if all these streams is what is making my memory usage increase month after month or if it can be something else.
The using statement takes care of closing the IDisposable object that it opens. This is not the source of the potential memory leak you're observing.
I'm new to Streams and in the program i'm developing requires reading data from a hex file.
File=level.dat
The code im using:
FileStream fs;
private void Form1_Load(object sender, EventArgs e)
{
Main("PCWorld\\level.dat");
NbtTree nbtTree = new NbtTree();
Stream s = fs;
Stream destStream = new MemoryStream();
nbtTree.ReadFrom(s);
nbtTree.WriteTo(destStream);
}
void Main():
void Main(string filename)
{
// From MSDN Forums, slightly modified by me
try
{
string fileName = filename;
// Create random data to write to the file.
byte[] dataArray = new byte[100000];
new Random().NextBytes(dataArray);
using (FileStream
fileStream = new FileStream(fileName, FileMode.Create))
{
// Write the data to the file, byte by byte.
for (int i = 0; i < dataArray.Length; i++)
{
fileStream.WriteByte(dataArray[i]);
}
// Set the stream position to the beginning of the file.
fileStream.Seek(0, SeekOrigin.Begin);
// Read and verify the data.
for (int i = 0; i < fileStream.Length; i++)
{
if (dataArray[i] != fileStream.ReadByte())
{
MessageBox.Show("Failed to load " + fileName + " (MCPC.dll)\n\nReason: Failed to read bytes\nResult: Close();\nSoloution: Try again and/or tell DMP9 Software", "Error");
Close();
return;
}
fs = fileStream;
}
}
}
catch (OutOfMemoryException ex)
{
MessageBox.Show("Failed to load NBT++.PC.exe\n\nReason: Out of memory (System.OutOfMemoryException: " + ex.Message + ")\nResult: Close();\nSoloution: Your PC Does not have enough RAM to run NBT++", "Error");
Close();
}
}
My program has a reference of Substrate (https://code.google.com/p/substrate-minecraft/downloads/list) and that does most of the work, but its my code giving
the "Cannot access a closed file"
Any help?
Thanks...
Your problem is in:
Stream s = fs;
The fs filestream is closed in your Main method (using statement disposes the filestream). To fix this you should open a new filestream to read from the file:
Stream s = new FileStream("PCWorld\\level.dat", FileMode.Read);
When using
using (FileStream fileStream = new FileStream(fileName, FileMode.Create))
{...}
you are closing this filestream when you go out scope. So you have to re-open file to read
http://msdn.microsoft.com/en-us/library/yh598w02.aspx
So I have a Serializable class Student, and I want my ReadFromFile method to deserialize my file so I can know how many records I already have in my object, so that when I want to add new records to my array I can know what's the index of the last array and I can put my new record in the index number after that. the function gives me an error on the 2nd pass of "Console.WriteLine(st2[j].FName + " " + st2[j].LName);" and tells me
NullReferenceException was unhandled
and it just writes the first item in my record that I have, not the rest.
public static int ReadFromFile()
{
int j = 0;
string path = #"students.dat";
try
{
Students[] st2 = new Students[100];
BinaryFormatter reader = new BinaryFormatter();
FileStream input = new FileStream(path, FileMode.Open, FileAccess.Read);
st2 = (Students[])reader.Deserialize(input);
while (true)
{
st[j] = new Students();
Console.WriteLine(st2[j].FName + " " + st2[j].LName);
j++;
}
Console.WriteLine("there are " + j + "students in the file");
input.Close();
return j;
}
catch (FileNotFoundException)
{
Console.WriteLine("there are no student records yet.");
return j;
}
}
this is my Serialization method:
public static void WriteInFileFromInput(Students[] x)
{
string path = #"students.dat";
if (File.Exists(path))
{
BinaryFormatter Formatter = new BinaryFormatter();
FileStream output = new FileStream(path, FileMode.Append, FileAccess.Write);
Formatter.Serialize(output, st);
output.Close();
}
else
{
BinaryFormatter Formatter = new BinaryFormatter();
FileStream output = new FileStream(path, FileMode.CreateNew, FileAccess.Write);
Formatter.Serialize(output, st);
output.Close();
}
}
The proper loop should look like this (assuming the data was serialized correctly):
foreach (var student in st2) // Replaces the while loop in the OP
{
Console.WriteLine(student.FName + " " + student.LName);
++j;
}
However, I think there is an error in the serialization so this will still give a null reference exception.
If so, can you post the code that serializes the data?
I have an application A that generates a text file for tracing.
While, an application B needs read the same text file and attach in a mailmessage.
But I get the following error, when application B try read the text file:
IOException: The process cannot access the file 'filename' because it
is being used by another process
Any suggestions ? Maybe better use for FileMode and FileAccess?
Application A
if (File.Exists(nFile2)) File.Delete(nFile2);
traceFile2 = File.Open(nFile2, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);
if (traceFile2 != null)
{
var twt2 = new TextWriterTraceListener(traceFile2);
// http://www.helixoft.com/blog/archives/20
try
{
if (twt2.Writer is StreamWriter)
{
(twt2.Writer as StreamWriter).AutoFlush = true;
}
}
catch { }
var indiceTraceFile2 = Trace.Listeners.Add(twt2);
System.Diagnostics.Trace.WriteLine("INICIO: " + DateTime.Now.ToString());
Application B
using (FileStream fileStream = File.Open(f, FileMode.Open, FileAccess.ReadWrite, FileShare.Read))
{
var messageAttachment = new Attachment(fileStream, Path.GetFileName(f));
msgMail.Attachments.Add(messageAttachment);
}
You need to make sure that both the service and the reader open the log file non-exclusively. Notice line 2 of App A and Line 1 of App B
Application A:
if (File.Exists(nFile2))
File.Delete(nFile2);
traceFile2 = new FileStream(nFile2, FileMode.Open, FileAccess.Write, FileShare.ReadWrite);
if (traceFile2 != null)
{
var twt2 = new TextWriterTraceListener(traceFile2);
// http://www.helixoft.com/blog/archives/20
try
{
if (twt2.Writer is StreamWriter)
{
(twt2.Writer as StreamWriter).AutoFlush = true;
}
}
catch { }
var indiceTraceFile2 = Trace.Listeners.Add(twt2);
System.Diagnostics.Trace.WriteLine("INICIO: " + DateTime.Now.ToString());
and Application B:
using (FileStream fileStream = new FileStream(f, FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite))
{
var messageAttachment = new Attachment(fileStream, Path.GetFileName(f));
msgMail.Attachments.Add(messageAttachment);
}
Of course you can read and write from/to the same file at the same time (by different threads/processes).
Here is a sample code. Just see how FileStream is created.
string fname = "a.txt";
//WRITER
Task.Factory.StartNew(() =>
{
var f = new FileStream(fname, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite);
var s = new StreamWriter(f);
long l = 0;
while (true)
{
s.WriteLine(l++);
s.Flush();
Task.Delay(1000).Wait();
}
});
//READER
Task.Factory.StartNew(() =>
{
Task.Delay(1000).Wait();
var f = new FileStream(fname, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
var s = new StreamReader(f);
while (true)
{
var line = s.ReadLine();
if (line == null) { Task.Delay(100).Wait(); continue; };
Console.WriteLine("> " + line + " <");
}
});
It seems that you are not using the Dispose() and Close() methods of StreamWriter class to release the file.
You need to release control of the file from Program A. Try closing or disposing the streamwriter when you finish.
Or you might attempt using as is described in the answer to this question: Releasing access to files
I am trying to make a simple software which stores data in a TXT log file.
This is my code
FileStream fs = null;
StreamWriter fw = null;
try
{
fs= new FileStream(Environment.GetFolderPath(Environment.SpecialFolder.Desktop)+"/textme.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite);
fw = new StreamWriter(fs);
fw.Write("sadadasdsadsadsadas");
for (int i = 0; i < AnimalShelter.AnimalList.Count; i++)
{
fw.WriteLine("<chipNr>" + AnimalShelter.AnimalList[i].ChipRegistrationNumber + "<chipNr>");
Console.WriteLine("<chipNr>" + AnimalShelter.AnimalList[i].ChipRegistrationNumber + "<chipNr>");
}
}
catch(IOException)
{
MessageBox.Show("ERROR THROWN");
}
finally
{
if (fs!= null) fs.Close();
// if (fw != null) fw.Close();
}
What I achieved is: the file gets created, but nothing gets written in it.
I checked a lot of posts but I could not find any particular help.
Adding a call to Flush the stream works. This is because you are wrapping the FileStream. StreamWriter will write to the FileStream, but you need to indicate when to send the Stream to the actual file. Also, you can exchange your try finally with a using:
try
{
using (var fs = new FileStream(Environment.GetFolderPath(Environment.SpecialFolder.Desktop)+"/textme.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
using (var fw = new StreamWriter(fs))
{
fw.Write("sadadasdsadsadsadas");
for (int i = 0; i < AnimalShelter.AnimalList.Count; i++)
{
fw.WriteLine("<chipNr>" + AnimalShelter.AnimalList[i].ChipRegistrationNumber + "<chipNr>");
Console.WriteLine("<chipNr>" + AnimalShelter.AnimalList[i].ChipRegistrationNumber + "<chipNr>");
}
fw.Flush(); // Added
}
}
}
catch(IOException)
{
MessageBox.Show("ERROR THROWN");
}
Enclose your StreamWriter in an using block to be sure that everything is correctly closed at the end of the file usage, also I don't think you need to create a FileStream for this to work.
try
{
string fileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "textme.txt")
using(fw = new StreamWriter(fileName, true))
{
......
}
}
catch(IOException)
{
MessageBox.Show("ERROR THROWN");
}
Note that the StreamWriter has a constructor that accepts two parameters, the name of the file to create/open and a flag to indicate that the file should be opened in append mode or overwritten
See StreamWriter docs
Always use using (as mentioned already) and you won't run into problems (or have to think about it)...
using (FileStream fs = new FileStream(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "/textme.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite))
using (StreamWriter fw = new StreamWriter(fs))
{
fw2.Write("sadadasdsadsadsadas");
}
(also you could have closed the writer instead of filestream which should've worked)
The problem is as I far as I can tell...
FileStream.Close is actually Stream.Close - and that calls Dispose but it ain't virtual, so does some general cleanup.
FileStream.Dispose which is called implicitly when you use using - does specific Flush and then Close/Dispose - so does proper specific cleanup.
You can avoid any of that via using as that is generally recommended pattern (and frankly never got me into any of these)
Indeed, Flush() is the answer; however, I would use File.WriteAllLines() instead.
try
{
var fileName = Environment.GetFolderPath(Environment.SpecialFolder.Desktop)+"/textme.txt";
var lines = AnimalShelter.AnimalList.Select(o=> "<chipNr>" + o.ChipRegistrationNumber + "</chipNr>");
File.WriteAllLines(fileName, lines);
foreach(var line in lines)
Console.WriteLine(line);
}
catch(IOException)
{
MessageBox.Show("ERROR THROWN");
}
Try using this - just replace the array:
try
{
using (Stream fs = new FileStream(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "/textme.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
using (StreamWriter sw = new StreamWriter(fs))
{
int[] test = new int[] { 0, 12, 23, 46 };
sw.Write("sadadasdsadsadsadas");
for (int i = 0; i < test.Length; i++)
{
sw.WriteLine("<chipNr>" + test[i] + "<chipNr>");
Console.WriteLine("<chipNr>" + test[i] + "<chipNr>");
}
sw.Close();
}
fs.Close();
}
}
catch (IOException)
{
MessageBox.Show("ERROR THROWN");
}