7

I suppose my title isn't that clear.

I'll try to explain:

I can write and read a file using a FileStream

FileStream fs = new FileStream("C:\\Users\\Public\\text.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);

private void button1_Click(object sender, EventArgs e)
{
    fs.Seek(0,0);
    StreamReader sr = new StreamReader(fs);
    textbox.Text = sr.ReadToEnd();
}

private void button2_Click(object sender, EventArgs e)
{
    StreamWriter sw = new StreamWriter(fs);
    sw.Write(textbox.Text);
    sw.Flush();
}

This way other programs can't use the file, but I also can't delete content. Writing to it only adds the string, it doesn't replace the content.

Or I can do it without a FileStream:

private void button1_Click(object sender, EventArgs e)
{
    StreamReader sr = new StreamReader("C:\\Users\\Public\\text.txt");
    textBox1.Text = sr.ReadToEnd();
    sr.Close();
}

private void button2_Click(object sender, EventArgs e)
{
    StreamWriter sw = new StreamWriter("C:\\Users\\Public\\text.txt", false);
    sw.Write(textBox1.Text);
    sw.Close();
}

This way, the content of the file is replaced, but it has no lock on the files.

But I want both. What is the solution?

pikachu
  • 1,031
  • 2
  • 11
  • 20

3 Answers3

15

In your first example, you need to reset the stream before you write to it in order to replace the file contents, instead of appending to it:

private void button2_Click(object sender, EventArgs e)
{
    fs.Seek(0,0);
    fs.SetLength(Encoding.UTF8.GetBytes(textbox.Text).Length));
    StreamWriter sw = new StreamWriter(fs);
    sw.Write(textbox.Text);
    sw.Flush();
}
Oded
  • 489,969
  • 99
  • 883
  • 1,009
  • 1
    No, I don't think this is a good way to do it. What you suggest, for as far as I tested worked like the "insert" mode in texteditors. If my previous text was much longer, only the first characters will be overwritten. For example the file contains "OOOOOOOOOO" and I write "IIIII" to the file in my program, the file will contain "IIIIOOOOO". – pikachu Nov 28 '11 at 16:30
  • 1
    @pikachu - You need to use `SetLength` on the `FileStream` in order to truncate it. Answer updated, assuming `UTF8`. – Oded Nov 28 '11 at 17:02
1

If you truncate the stream down to 0, it will also work and no need to calculate the new file size in bytes.

fs.Seek(0,0);
fs.SetLength(0);
Victor Lee
  • 388
  • 2
  • 14
0

If you want overwrite content of file, you need to do two things:

  1. set EndOfFile to 0,
  2. set Size of file to 0.

If you use FileStream FileMode.Truncate, it will set allocation size and eof to 0 by call only one system function. See from procMon (SysInteranls): operationSeqence_Truncate

If you use FileStream FileMode.OpenOrCreate (or Open) and using fs.Seek(0,0) + fs.SetLength(0) or only fs.SetLength(0), it will do the same by calling now two system functions. See from procMon (SysInteranls): operationSeqence-SetLengthWithSeekOrOnlySetLength

I prefare to use the first way. Code is clear and no additional function is calling. We set mode and nothing else.

using (var fileStream = new FileStream(path, FileMode.Truncate, FileAccess.Write, FileShare.Read))
using (var binaryWriter = new BinaryWriter(fileStream, Encoding.Unicode))
{
  binaryWriter.Write(bytes, 0, bytes.Length);
}