Read and write to a file in the same stream - c#

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.

Related

C# Text Writer writes at the start of the file

My class which holds the constructor method of writing to a file
class Writer
{
public Writer(string filename, List<string> data)
{
FileStream ostrm;
StreamWriter writer;
TextWriter oldOut = Console.Out;
try
{
ostrm = new FileStream("C:/Users/kyle/Desktop/ConferenceSoftware/" + filename + ".txt", FileMode.OpenOrCreate, FileAccess.Write);
writer = new StreamWriter( ostrm );
}
catch (Exception e)
{
Console.WriteLine("Cannot open " + filename + ".txt for writing");
Console.WriteLine(e.Message);
return;
}
Console.SetOut(writer);
foreach (var _data in data)
{
Console.WriteLine( _data );
}
Console.SetOut(oldOut);
writer.Close();
ostrm.Close();
}
}
Inside my main method:
List<string> dataToAdd = new List<string>();
dataToAdd.Add("Example");
new Writer(Settings.ConferenceRoomName, dataToAdd);
However, if I already have text inside the file, instead appending to the file from the last line, it does it from the first line, ie:
Example // new added through method
Line that already exists // already in file
Line that already exists // already in file
// this is where I wanted it but it goes to the top
Any help would be appreciated, I don't see where I could target what line to start writing at.
Thanks in advance.
You need to use FileMode.Append instead of OpenOrCreate:
ostrm = new FileStream("C:/Users/kyle/Desktop/ConferenceSoftware/" +
filename + ".txt", FileMode.Append, FileAccess.Write);
See documentation (about FileMode.Append):
Opens the file if it exists and seeks to the end of the file, or creates a new file. This requires FileIOPermissionAccess.Append permission. FileMode.Append can be used only in conjunction with FileAccess.Write...
So it will also create the file if it does not exist.
If you don't want to create a non-existing file, you can check if it exists using File.Exists() before opening the stream.
When you create a new FileStream with FileMode.OpenOrCreate, it writes over the existing file. If you would like to append to the file, use FileMode.Append instead:
FileMode.Append: Opens the file if it exists and seeks to the end of the file, or creates a new file. This requires FileIOPermissionAccess.Append permission.
ostrm = new FileStream("C:/Users/kyle/Desktop/ConferenceSoftware/" + filename + ".txt", FileMode.Append, FileAccess.Write);
You want file mode Append instead of OpenOrCreate:
ostrm = new FileStream("C:/Users/kyle/Desktop/ConferenceSoftware/" + filename + ".txt", FileMode.Append, FileAccess.Write);
Both will create a new file if it doesn't exist, the difference is that OpenOrCreate starts writing at the beginning of the file and Append starts writing at the end of the file.
Reference: FileMode Enumeration

StreamWriter cannot write into a file although it is closed

I have the following problem:
I use this code to open a file and write to it:
using (FileStream fileStream = new FileStream(saveDir + #"\" + saveFile, FileMode.Open, FileAccess.ReadWrite,FileShare.ReadWrite))
{
StreamWriter streamWriter = new StreamWriter(fileStream);
streamWriter.Write("Test");
streamWriter.Close();
}
but in the "using" line it tells me that it can not open the file because it is used by another process but the file is not open and isn't used. What's wrong?
I searched around this forum and the internet but I can't find a solution.
You could try using FileMode.OpenOrCreate instead of creating the file "manually":
using (FileStream fileStream = new FileStream(saveDir + #"\" + saveFile,
FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
{
StreamWriter streamWriter = new StreamWriter(fileStream);
streamWriter.Write("Test");
streamWriter.Close();
}

The process cannot access the file because it is being used by another process (File is created but contains nothing)

using System.IO;
class test
{
public static void Main()
{
string path=#"c:\mytext.txt";
if(File.Exists(path))
{
File.Delete(path);
}
FileStream fs=new FileStream(path,FileMode.OpenOrCreate);
StreamWriter str=new StreamWriter(fs);
str.BaseStream.Seek(0,SeekOrigin.End);
str.Write("mytext.txt.........................");
str.WriteLine(DateTime.Now.ToLongTimeString()+" "+DateTime.Now.ToLongDateString());
string addtext="this line is added"+Environment.NewLine;
File.AppendAllText(path,addtext); //Exception occurrs ??????????
string readtext=File.ReadAllText(path);
Console.WriteLine(readtext);
str.Flush();
str.Close();
Console.ReadKey();
//System.IO.IOException: The process cannot access the file 'c:\mytext.txt' because it is //being used by another process.
// at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
}
}
Try This
string path = #"c:\mytext.txt";
if (File.Exists(path))
{
File.Delete(path);
}
{ // Consider File Operation 1
FileStream fs = new FileStream(path, FileMode.OpenOrCreate);
StreamWriter str = new StreamWriter(fs);
str.BaseStream.Seek(0, SeekOrigin.End);
str.Write("mytext.txt.........................");
str.WriteLine(DateTime.Now.ToLongTimeString() + " " +
DateTime.Now.ToLongDateString());
string addtext = "this line is added" + Environment.NewLine;
str.Flush();
str.Close();
fs.Close();
// Close the Stream then Individually you can access the file.
}
File.AppendAllText(path, addtext); // File Operation 2
string readtext = File.ReadAllText(path); // File Operation 3
Console.WriteLine(readtext);
In every File Operation, The File will be Opened and must be Closed prior Opened. Like wise in the Operation 1 you must Close the File Stream for the Further Operations.
You are writing to the file prior to closing your filestream:
using(FileStream fs=new FileStream(path,FileMode.OpenOrCreate))
using (StreamWriter str=new StreamWriter(fs))
{
str.BaseStream.Seek(0,SeekOrigin.End);
str.Write("mytext.txt.........................");
str.WriteLine(DateTime.Now.ToLongTimeString()+" "+DateTime.Now.ToLongDateString());
string addtext="this line is added"+Environment.NewLine;
str.Flush();
}
File.AppendAllText(path,addtext); //Exception occurrs ??????????
string readtext=File.ReadAllText(path);
Console.WriteLine(readtext);
The above code should work, using the methods you are currently using. You should also look into the using statement and wrap your streams in a using block.
File.AppendAllText does not know about the stream you have opened, so will internally try to open the file again. Because your stream is blocking access to the file, File.AppendAllText will fail, throwing the exception you see.
I suggest you used str.Write or str.WriteLine instead, as you already do elsewhere in your code.
Your file is created but contains nothing because the exception is thrown before str.Flush() and str.Close() are called.
using (var fs = new FileStream(filePath, FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
using (var sw = new StreamWriter(fs))
{
sw.WriteLine(message);
}

Streamwriter not throwing exception

In the following, streamwriter is not throwing an exception if the file does not exist.
I expected it to raise an exception, why doesn't it and how can I get it to do so?
var fileName = HttpContext.ApplicationInstance.Server.MapPath("~/App_Data/emails.txt");
FileStream fs = new FileStream(fileName, FileMode.Append);
StreamWriter sw = new StreamWriter(fs);
sw.WriteLine(String.Format("{0}\t{1}", email, name));
sw.Flush();
sw.Close();
fs.Close();
Why?
FileStream fs = new FileStream(fileName, FileMode.Append);
This will create the file if it doesn't exist (and append to it if it does).
Assuming from your post (there is no question in it!) you don't want it to create a file first call File.Exists to ensure the file exists.
If you want to make sure you're appending to an existing file, use FileMode.Open and then Seek to the end before writing.
With File.Exists there is a (very slim) chance of an other process deleting the file after checking but before the construction of the FileStream.
Try this:
try
{
var fileName = HttpContext.ApplicationInstance.Server.MapPath("~/App_Data/emails.txt");
if (System.IO.File.Exists(fileName ))
{
FileStream fs = new FileStream(fileName, FileMode.Append);
StreamWriter sw = new StreamWriter(fs);
sw.WriteLine(String.Format("{0}\t{1}", email, name));
sw.Flush();
sw.Close();
fs.Close();
}
else
{
//Throw error here
}
}
catch()
{
}

FileStream.WriteLine() is not writing to file

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");
}

Categories

Resources