5

I am not sure how can I solve my problem. From time to time I get the error: "The process cannot access the file 'xxxx' because it is being used by another proces".

Here is my method where the error happens:

private static void write_history(int index, int time_in_sec, int[] sent_resources)
        {
            string filepath = "Config\\xxx.txt";
            int writing_index = 0;

            if (File.Exists(filepath))
            {
                System.Threading.Thread.Sleep(5000);
                StreamReader reader = new StreamReader(new FileStream(filepath, FileMode.Open, FileAccess.Read, FileShare.Read));
                string temp = reader.ReadToEnd();
                reader.Close();

                for (int i = 0; i < 20; i++)
                {
                    if (temp.IndexOf("<hst_" + i.ToString() + ">") == -1)
                    {
                        writing_index = i;
                        break;
                    }
                }
            }

            System.Threading.Thread.Sleep(5000);
            // write to the file
            StreamWriter writer = new StreamWriter(filepath, true);
            writer.WriteLine("<hst_" + writing_index.ToString() + ">" + DateTime.Now.AddSeconds(time_in_sec).ToString() + "|" + sent_resources[0] + "|" + sent_resources[1] + "|" + sent_resources[2] + "|" + sent_resources[3] + "</hst_" + writing_index.ToString() + ">");
            writer.Close();
        }

And the error I get:

************** Exception Text **************
System.IO.IOException: The process cannot access the file 'Config\\xxx.txt' because it is being used by another process.
   at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath)
Martin Mulder
  • 12,642
  • 3
  • 25
  • 54
Doctorslo
  • 287
  • 2
  • 3
  • 12
  • 4
    Try putting your `StreamReader` in a `using` block – tnw Apr 29 '13 at 18:09
  • Check out: http://stackoverflow.com/questions/3560651/whats-the-least-invasive-way-to-read-a-locked-file-in-c-sharp-perhaps-in-unsaf – George Johnston Apr 29 '13 at 18:10
  • Are you building/re-building your project quickly? Or aborting your program regularly? –  Apr 29 '13 at 18:14
  • Unrelated to the question, what is the point of sleeping for 5 seconds twice? If it's an effort to make threads behave together there are better ways to waiting for threads to complete. – Brad Apr 29 '13 at 18:17
  • did you try StreamReader.Close() - MSDN -http://msdn.microsoft.com/en-us/library/system.io.streamreader.close.aspx – aked Apr 29 '13 at 18:20
  • @Brad I agree, my guess is it was a half-ass attempt at fixing the issue at hand. OP you've got to remove those... a full 10 seconds sleeping in that method is ridiculous unless you have a *really* good reason for it to be there. – tnw Apr 29 '13 at 18:20
  • 1
    @simplecoder Uhhh... he has `reader.Close();` right there in his code. – tnw Apr 29 '13 at 18:21
  • @Doctorslo: It your function called in a multithreaded environment? – Martin Mulder Apr 29 '13 at 18:35

5 Answers5

9

If you have made sure that you are genuinely opening and closing the file correctly, the most likely culprit is your virus detector. Virus detectors are notorious for observing that a log file has changed, opening it up to search it for a virus, and then while it is being read by the virus checker, an attempt to write to the file fails.

If that's the case, then I would ask the vendor of your virus checker what their recommended workaround is.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 2
    Good point. OP, if you think this might be the case, it's worth it to run [Process Explorer](http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx) and verify that this is the case. – tnw Apr 29 '13 at 18:23
3
  1. Use using around all your objects that are IDisposable. using will ALWAYS call the method Dispose, even if there is an exception.
  2. You did close your reader, but did not close the filestream.
  3. This code can be made much shorter, see my second example at the bottom of my answer.

    private static void write_history(int index, int time_in_sec, int[] sent_resources)
    {
        string filepath = "Config\\xxx.txt";
        int writing_index = 0;
    
        if (File.Exists(filepath))
        {
            System.Threading.Thread.Sleep(5000);
            using(FileStream stream = new FileStream(filepath, FileMode.Open, FileAccess.Read, FileShare.Read)
            using(StreamReader reader = new StreamReader(stream))
            {
                 string temp = reader.ReadToEnd();
            }
    
            for (int i = 0; i < 20; i++)
            {
                if (temp.IndexOf("<hst_" + i.ToString() + ">") == -1)
                {
                    writing_index = i;
                    break;
                }
            }
        }
    
        System.Threading.Thread.Sleep(5000);
        // write to the file
        using(StreamWriter writer = new StreamWriter(filepath, true))
        { 
             writer.WriteLine("<hst_" + writing_index.ToString() + ">" + DateTime.Now.AddSeconds(time_in_sec).ToString() + "|" + sent_resources[0] + "|" + sent_resources[1] + "|" + sent_resources[2] + "|" + sent_resources[3] + "</hst_" + writing_index.ToString() + ">");
        }
    }
    

Shorter version:

    private static void write_history(int index, int time_in_sec, int[] sent_resources)
    {
        string filepath = "Config\\xxx.txt";
        int writing_index = 0;

        if (File.Exists(filepath))
        {
            System.Threading.Thread.Sleep(5000);
            string temp = File.ReadAllText(filepath);

            for (int i = 0; i < 20; i++)
            {
                if (temp.IndexOf("<hst_" + i.ToString() + ">") == -1)
                {
                    writing_index = i;
                    break;
                }
            }
        }

        System.Threading.Thread.Sleep(5000);
        // write to the file
        File.WriteAllText(filepath, "<hst_" + writing_index.ToString() + ">" + DateTime.Now.AddSeconds(time_in_sec).ToString() + "|" + sent_resources[0] + "|" + sent_resources[1] + "|" + sent_resources[2] + "|" + sent_resources[3] + "</hst_" + writing_index.ToString() + ">");
    }

In case of multi threading:

private static readonly object _syncLock = new object();

private static void write_history(int index, int time_in_sec, int[] sent_resources)
{
   lock(_syncLock)
   {
        string filepath = "Config\\xxx.txt";
        int writing_index = 0;

        if (File.Exists(filepath))
        {
            System.Threading.Thread.Sleep(5000);
            string temp = File.ReadAllText(filepath);

            for (int i = 0; i < 20; i++)
            {
                if (temp.IndexOf("<hst_" + i.ToString() + ">") == -1)
                {
                    writing_index = i;
                    break;
                }
            }
        }

        System.Threading.Thread.Sleep(5000);
        // write to the file
        File.WriteAllText(filepath, "<hst_" + writing_index.ToString() + ">" + DateTime.Now.AddSeconds(time_in_sec).ToString() + "|" + sent_resources[0] + "|" + sent_resources[1] + "|" + sent_resources[2] + "|" + sent_resources[3] + "</hst_" + writing_index.ToString() + ">");
    }
 }
Martin Mulder
  • 12,642
  • 3
  • 25
  • 54
  • Thank you. Your answer fits my question. I am not sure if this would work, but I'll give it a try. Also thanks for explaining using statement. (Cannot test is so fast, as I said sometimes happen and sometimes not :o) – Doctorslo Apr 29 '13 at 18:48
  • I tested it and crash happened again :( – Doctorslo Apr 30 '13 at 08:56
  • @DoctorSlo: Yesterday I asked: It your function called in a multithreaded environment? Can you give me that answer, please? – Martin Mulder Apr 30 '13 at 08:59
  • @DoctorSlo: In case you are using a multithreaded environment, I added another solution which is synchronized. – Martin Mulder Apr 30 '13 at 09:05
  • @Doctorslo: Another thing hit me: Do you run multiple instances of this application? If so, just at one machine or multiple machines? – Martin Mulder May 01 '13 at 09:40
1

my guess is that your FileStream(the one you're passing into your StreamReader constructor) is not getting closed

StreamReader reader = new StreamReader(new FileStream(filepath, FileMode.Open, FileAccess.Read, FileShare.Read));

Put that statement in a using statement, to make sure all your ends are tied

using(StreamReader reader = new StreamReader(new FileStream(filepath, FileMode.Open, FileAccess.Read, FileShare.Read)))
{
    //the using statement will handle the closing for you
}
  • 1
    Though using "using" is certainly best practice here, I wonder how it can solve the problem. The OP does close the reader, and closing the reader closes the underlying stream, which in turn will dispose the stream. So given that there is no exception that prevents the code to reach the close statement (the OP doesn't mention any), how could the using statements help solving the problem? – Matthias Apr 29 '13 at 21:31
1

Your method is not thread-safe. If you're accessing this method in a multi-threaded fashion, your threads could be attempting the file access at the same time. In addition to alexn's answer of properly disposing of your StreamReader, also consider using a static object outside of your method in your class and then simply locking on that before you access the file.

private static object lockObject = new object();

private static void write_history(int index
{
    lock(lockObject)
    {
        // Access file here
    }
}
Tombala
  • 1,660
  • 9
  • 11
  • Meh. I suppose this is valid, though OP didn't mention anything about multi-threading. I won't -1 but I wont +1 either. – tnw Apr 29 '13 at 18:22
  • Also I don't see anything shared among multiple threads (No need lock for files since you already get an exception if you try to oepn the same file multiple times for write) – I4V Apr 29 '13 at 18:30
  • tnw, I went with the assumption that a history writing static method could be called from multiple threads. That's why I said "If you're accessing this method in a multi-threaded fashion". That summarized my assumption and sets the context for the answer. I'm not sure I follow the point of your comment I4V. You do have to lock your access point if you want both writes to the file to succeed. I'm not saying lock the file, I'm talking about thread-locking the code. Maybe you misunderstood me? – Tombala Apr 29 '13 at 18:44
  • Thanks, but this method is used only in one thread. I am sure multi threading is nt a problem. – Doctorslo Apr 29 '13 at 18:47
  • I was having the same issue. And its working file not using this approach. Thanks a lot.@Tombala – Nayan Dey Jun 02 '20 at 07:23
1

Either you can use "using" or you can force the Garbage collector to release all the references. This has resolved my issue. Review your code before applying process level or thread level changes.

example:

using(StreamWriter writer....)
{
  Your Code....
}
this.deleteFiles(filepath);

Or:

GC.Collect();
this.deleteFiles(filepath);
STT LCU
  • 4,348
  • 4
  • 29
  • 47
Unais.N.I
  • 61
  • 3