0

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();
       }           
   }
pstrjds
  • 16,840
  • 6
  • 52
  • 61
Sohel
  • 656
  • 2
  • 11
  • 31
  • 1
    Is the error being thrown from the write code or the read code? – laptou Apr 27 '18 at 20:58
  • I assume these two blocks of code are inside two different methods. Could you please show how and in what order you're invoking those methods and on what line your debugger is throwing the error? (Assuming that youre using the debugger to step through your code, line by line) – 8protons Apr 27 '18 at 21:00
  • @333 write, in the second block of code where it says "I/O error while writing the file" – Blake Thingstad Apr 27 '18 at 21:00
  • When you close all instances of your program and try to delete the file in File Explorer, does it complain? – laptou Apr 27 '18 at 21:02
  • 1
    Note you also potentially call `Close` on a disposed object and are also disposing them two times. You are calling `Close` and `Dispose` on your reader and writer inside the try block but are not setting them to `null` and then in your finally you are calling `Close` and `Dispose` if the object is not `null` – pstrjds Apr 27 '18 at 21:04
  • If you what you have posted here is your actual code, you are opening the file for reading twice but only closing it once. You open it just before the try statement and then just again after the try. That is most likely causing you the problem. It is okay to open a file for multiple readers, but if any of them have the file open then you won't be able to write to it. In your case it is opened twice for reading but only closed once. – pstrjds Apr 27 '18 at 21:07
  • Thanks for all of your feedback. I will post the entire code after cleaning it up a bit, – Sohel Apr 27 '18 at 21:14
  • 1
    @Sohel - I don't think posting the entire code is necessary. Actually one of the best ways to solve a problem like this is to start removing code or try to create a small program that reproduces the problem (see [MCVE](https://stackoverflow.com/help/mcve)) Often when trying to create the MCVE we actually figure out what is going wrong. – pstrjds Apr 27 '18 at 21:17
  • Thanks @pstrjds, I will check the link you've provided. The problem is resolved after removing an extra stream reader variable I was declaring before the first Try Block. Now I see that you and Patrick both have mentioned it. Thank you. – Sohel Apr 27 '18 at 21:33

2 Answers2

4

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

Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
1

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()

8protons
  • 3,591
  • 5
  • 32
  • 67
  • While it is true that `Dispose` is being called multiple times (including another round of it in the `finally` block) this wouldn't give the exception of trying to write to a file that is open. – pstrjds Apr 27 '18 at 21:09
  • @pstrjds That error about writing to a file that is open was not from the compiler. The OP wrote that himself (check out his/her comment and the exception string literal they are throwing) so that may not even be the actual reason at all. – 8protons Apr 27 '18 at 21:10
  • correct, the OP specifically mentions runtime error, i.e. exception. Calling Dispose multiple times is not what is leading to an I/O error. I am not disagreeing with you that the code needs to be cleaned up, I am just stating that this would not really fix the problem. The problem is that the file is clearly opened twice for reading but only closed once, which leads to a runtime error when trying to write to the file. – pstrjds Apr 27 '18 at 21:12
  • Thanks for pointing this Close() method's calling Dispose(true). I have taken out Dispose() after the Close method now. The error still exists, so trying to find out what it is and how to resolve it. – Sohel Apr 27 '18 at 21:12
  • @pstrjds Ah okay, that makes sense. Thank you for explaining that, I appreciate it – 8protons Apr 27 '18 at 21:14
  • 1
    @Sohel - Follow Patrick's answer. You are opening the file twice but only closing it once. – pstrjds Apr 27 '18 at 21:14
  • 2
    @8protons - No problem - my goal was to explain to you as well as the OP what the problem actually is related to. That way we all learn :) – pstrjds Apr 27 '18 at 21:15