Tan Poh Heng
Tan Poh Heng

Reputation: 37

Why using using() {} around StreamReader.Read allows the file to be deleted afterwards?

So I was trying out Windows forms for a school project and kept running into the error:

System.IO.IOException('The process cannot access the file 'C:\XXXX\YYYY.txt' because it is being used by another process.'

when trying to delete files (File.Delete(path);) via a button_click event.

Turns out, when I changed the following method from:

private void updateTxt(){
  String tempStore = "";
  iDLbl1.Text = "ID:" + id;//iDLbl1 is ID Label 1
  try
  {
      StreamReader Reader = new StreamReader(path);
      while (!Reader.EndOfStream)
        { tempStore += Reader.ReadLine() + "\n"; }
  }
  catch { noIDLbl.Visible = true; }
  rTxtBox.Text = tempStore;//rTxtBox is Rich Text Box
} 

to

private void updateTxt(){
    String tempStore = "";
    iDLbl1.Text = "ID:" + id;//iDLbl1 is ID Label 1
    try
    {
        using(StreamReader Reader = new StreamReader(path))
        {
            while (!Reader.EndOfStream)
            { tempStore += Reader.ReadLine() + "\n"; }
        }

    }
    catch { noIDLbl.Visible = true; }
    rTxtBox.Text = tempStore;//rTxtBox is Rich Text Box
}

The exception stopped popping up. While the code works, I have no idea what causes this at all... The logic doesn't seem to click for me, so anyone knows why this happens or have a more logical solution?Ask for clarification if needed and Here's the constructor just in-case:

public FindID(String ID)
{
    id = ID;
    path = @"C:\XXXX\YYYY\"+ID+".txt";
    InitializeComponent();
    updateTxt();
}

Upvotes: 1

Views: 84

Answers (2)

StuartLC
StuartLC

Reputation: 107297

In the your first approach, since you aren't Close()ing or Dispose()ing your StreamReader, the associated file handle will be held until the StreamReader is collected by the garbage collector, which could be many seconds, or even minutes later (and please don't try and control or influence the GC).

In your second approach, the using scope Disposes (and closes) the StreamReader at the end of the scope (the closing } matching the using), which is correct practice when using any class which implements IDisposable. This then releases any handles to the file, allowing for its deletion. The using block also has the guarantees of a try / finally block, so Dispose will be called even if there is an IO Exception:

using(StreamReader Reader = new StreamReader(path)) // try {StreamReader Reader = ...}
{
     ...
} <- equivalent to finally {Reader.Dispose();}

However, since you seem to just want to immediately materialize all lines from a line delimited text file, you can do this in one step with File.ReadAllLines - i.e. no need for StreamReader at all:

var tempStore = string.Join(Environment.NewLine, File.ReadAllLines(path));

Upvotes: 6

Anirudha Gupta
Anirudha Gupta

Reputation: 9289

In the second code as soon your code block will execute StreamReader will be disposed. Since StreamReader will be disposed the file is not locked by your current process.

In your first code you can do same by dispose them at the end of your code.

Upvotes: 3

Related Questions