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");
}
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 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()
I'm trying to read and write to the same file in a way such that no other program can access the file in between:
FileStream fs = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
StreamReader sr = new StreamReader(fs);
StreamWriter sw = new StreamWriter(fs);
newString = sr.ReadToEnd() + "somethingNew";
sw.Write(newString);
fs.Close();
The file is never written to. If I debug I can see that the reader manages to fetch the contents of the file, but the writer does not seem to be able to write to the file. Nothing happens.
I've been looking at this question which seems to be the same as mine. However I'm not able to get it to work.
Just Flush your changes to file, Have sw.Flush(); before closing the stream. like:
string filePath = "test.txt";
FileStream fs = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
StreamReader sr = new StreamReader(fs);
StreamWriter sw = new StreamWriter(fs);
newString = sr.ReadToEnd() + "somethingNew";
sw.Write(newString);
sw.Flush(); //HERE
fs.Close();
You may see this post simultaneous read-write a file in C# (open multiple streams for reading and writing)
As mentioned above - just add the Flush() to force the data held in the stream to be written to the file. In a comment you mentioned that you had previously used a 'using' statement but this hadn't worked.
Briefly here's why:
A using statement automatically calls Flush() so you don't have
to.
When you dispose of a StreamReader (or StreamWriter) - like by using a 'using' statement - the inner stream object is also disposed and you lose the handle to the stream.
#EJS a simple static method that you can use to create a new file if it does not exist as well as write to the same file if it does exist
Simple usage
string path = #"C:\SomePath\Name.txt";
if (!System.IO.File.Exists(path))
{
WriteAndOrAppendText(path, "File Created");
}
else if (System.IO.File.Exists(path))
{
WriteAndOrAppendText(path, "New Boot.");
}
private static void WriteAndOrAppendText(string path, string strText)
{
if (!File.Exists(path))
{
using (StreamWriter fileStream = new StreamWriter(path, true))
{
fileStream.WriteLine(strText);
fileStream.Flush();
fileStream.Close();
}
}
else
{
using (StreamWriter fileStream2 = new StreamWriter(path, true))
{
fileStream2.WriteLine(strText);
fileStream2.Flush();
fileStream2.Close();
}
}
}
For being able to create a file, append to it, and read the data in it while still allowing an application to write to it, as I believe you are trying to do, here's a set up I created:
string path = #"C:\SomePath\MyLogFile.txt";
public static string Log(string Message)
{
try
{
if (File.Exists(path) == false)
File.Create(path).Close(); // need this .Close()!!!
logCounter++;
string logString = logCounter + " " + DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToShortTimeString() + ": " + Message + Environment.NewLine;
using (FileStream fs = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
{
using (StreamWriter sw = new StreamWriter(fs))
{
sw.Write(logString);
}
}
return logString; // only necessary so we can return an error in the Exception block
}
catch (Exception ex)
{
return "Logger: Cannot log data. " + ex.ToString();
}
}
It's actually required to use FileAccess.Write if you do FileMode.Append - instead of being able to use FileAccess.ReadWrite - but I found that didn't matter because whatever had been written would have been closed and flushed to the file, and I could still open the file and read it (it wouldn't be locked & blank) using these. I have sw.Write() because I have Environment.NewLine that I added into my logString, but I could've done sw.WriteLine() and removed that, if I had wanted to.
One caveat: File.Exists() has issues if the path is long - can't remember the limit, but just know that there is one, so don't put your file you're writing to several layers deep. Less is always better.
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
I simply want to merge all text files in a given directory, similar to the following command prompt command:
cd $directory
copy * result.txt
I've written the following code, which almost accomplishes what I want, but it's doing something strange. When the StreamWriter writes the first file (or when i = 0), it doesn't actually write any content - the file size remains 0 bytes, despite the first file being ~300 KB. However, the other file writes execute successfully.
If I compare the output from the command prompt to the output from the C# code in diff, you can see that a large block of text is missing. Additionally, the command prompt result is 1,044 KB where the C# result is 700 KB.
string[] txtFiles = Directory.GetFiles(filepath);
using (StreamWriter writer = new StreamWriter(filepath + "result.txt"))
{
for (int i = 0; i < txtFiles.Length; i++)
{
using (StreamReader reader = File.OpenText(txtFiles[i]))
{
writer.Write(reader.ReadToEnd());
}
}
}
Am I using the StreamWriter / StreamReader incorrectly?
Minimalistic implementation, reading the bytes and writing them instead of using a stream for reading - please note, that you should handle the IOException correctly to avoid misbehavior:
var newline = Encoding.ASCII.GetBytes(Environment.NewLine);
var files = Directory.GetFiles(filepath);
try
{
using (var writer = File.Open(Path.Combine(filepath, "result.txt"), FileMode.Create))
foreach (var text in files.Select(File.ReadAllBytes))
{
writer.Write(text, 0, text.Length);
writer.Write(newline, 0, newline.Length);
}
}
catch (IOException)
{
// File might be used by different process or you have insufficient permissions
}
Here, hope it helps you. Note: By copying from a stream to another you save some ram and greatly improve performance.
class Program
{
static void Main(string[] args)
{
string filePath = #"C:\Users\FunkyName\Desktop";
string[] txtFiles = Directory.GetFiles(filePath, "*.txt");
using (Stream stream = File.Open(Path.Combine(filePath, "result.txt"), FileMode.OpenOrCreate))
{
for (int i = 0; i < txtFiles.Length; i++)
{
string fileName = txtFiles[i];
try
{
using (Stream fileStream = File.Open(fileName, FileMode.Open, FileAccess.Read))
{
fileStream.CopyTo(stream);
}
}
catch (IOException e)
{
// Handle file open exception
}
}
}
}
}
I wrote your code , it works properly! only change the line :
using (StreamWriter writer = new StreamWriter(filepath + "result.txt"))
to:
using (StreamWriter writer = new StreamWriter(filepath + "/result.txt"))
i guess you can't see the file because it is saved in another folder .