简体   繁体   中英

C# file is being used by another process

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)

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.

  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() + ">");
    }
 }

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
}

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
    }
}

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM