0

I'm writing a program that uses text files in C#. I use a parser class as an interface between the file structure and the program. This class contains a StreamReader, a StreamWriter and a FileStream. I use the FileStream as a common stream for the reader and the writer, else these two will conflict when both of them have the file open.

The parser class has a class variable called m_path, this is the path to the file. I've checked it extensively, and the path is correct. OpenStreams() and and ResetStreams() work perfectly, however after calling CloseStreams() in the delete() function, the program goes to the catch clause, so File.Delete(m_path) won't get executed. In other situations the CloseStreams() function works perfectly. It goes wrong when I'm trying to close the StreamReader (m_writer), but it does give an exception (File is Already Closed).

   /**
     * Function to close the streams.
     */
    private void closeStreams() {
        if (m_streamOpen) {
            m_fs.Close();
            m_reader.Close();
            m_writer.Close(); // Goes wrong

            m_streamOpen = false;
        }
    }

   /**
     * Deletes the file.
     */
    public int delete() {
        try {
            closeStreams(); // Catch after this
            File.Delete(m_path);

            return 0;
        }
        catch { return -1; }
    }

I call the function like this:

parser.delete();

Could anybody give me some tips?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129

2 Answers2

0

File.Delete should work, either you didn't call your delete method, or m_path is an invalid path

uowzd01
  • 1,015
  • 10
  • 19
0

Your File.Delete(m_path); will never be called, because you get an exception here:

private void closeStreams() {
    if (m_streamOpen) {
        m_fs.Close();
        m_reader.Close();
        m_writer.Close(); // throws an exception here

        m_streamOpen = false;
    }
}

The exception is "Cannot access a closed file"

The cause is explained in the documentation of Close() in StreamReader:

Closes the System.IO.StreamReader object and the underlying stream, and releases any system resources associated with the reader.

There are also some articles about this behaviour:

Does disposing streamreader close the stream?

Is there any way to close a StreamWriter without closing its BaseStream?

Can you keep a StreamReader from disposing the underlying stream?

Avoiding dispose of underlying stream

You should consider re-writing your code and use using() statements.

However, I experimented a bit with your code, and it worked with calling Close() in other order:

m_writer.Close();
m_reader.Close();
m_fs.Close();

However, I assume that this works only by coincidence (I used .NET 4.0 and probably this will not work in another .NET version). I would strongly advice to not do it in this way.

I tested this:

using (FileStream fs = new FileStream(m_path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None))
using (StreamReader reader = new StreamReader(fs))
using (StreamWriter writer = new StreamWriter(fs))
{
  // so some work here

}

File.Delete(m_path);

But, I know that this may not be for you, since you may want the read and write streams available as fields in your class.

At least, you have some samples to start with ...

Community
  • 1
  • 1
Rainer Schaack
  • 1,558
  • 13
  • 16
  • Thanks for the answer! I'd like to keep my streams open indeed, since it gets used a lot. If I understand it correctly, by closing the FileStream (m_fs) I automatically close the streams of m_reader and m_writer, so that's why it gives that exception? – abstract christmas tree Apr 23 '15 at 12:11
  • The other way around: m_reader.Close(); closes m_fs. I did some further checks: if I swap (in my example code with using (... the 2nd and 3rd line, I also get an exception here. So probably changing the order (first close writer, then reader, the file stream) may really be a viable solution. Just do some testing and experimenting ... And as Nils suggested: add some catch() code (or for first testing, completely remove all exception handling, which is IMHO better for experimenting than catch all and ignore any error (like in your code) – Rainer Schaack Apr 23 '15 at 13:39
  • All right, I think I understand it. Thanks for the help! Good suggestion btw to disregard try-catch clauses for first time testing, should come in handy in the future. – abstract christmas tree Apr 23 '15 at 16:36
  • When you Close() or Dispose() the writer it probably does a Flush(). When the reader is closed/disposed it also closes/disposes the stream, so if that is done before closing/disposing the writer it's implied Flush() may be what blows up on you. That would explain why closing or disposing the writer first (also inner-most using) works. The reader doesn't need to flush, so it is more likely to tolerate when the stream is already closed/disposed when it is asked to close/dispose. – Rob Parker Mar 22 '16 at 22:58