Search code examples
c#exceptioniowaitioexception

Avoid "file in use by another process" IO exception


The code that I have included below successfully writes to a CSV file. But if the CSV file that I am writing to happens to be open in Excel, I get a System.IO.Exception that indicates that "the file is being used by another process."

How can I change my code so that the program will continuing running and wait until the CSV is no longer open in Excel?

private void timer1_Tick(object sender, EventArgs e)
    {
        int actmonth, actyear, actsecond;
        System.DateTime fecha = System.DateTime.Now;
        actmonth = fecha.Month;
        actyear = fecha.Year;
        if (actmonth <= 9)
        {
            valorfechaact = System.Convert.ToString(actyear) + "00" + System.Convert.ToString(actmonth);
        }
        else
        {
            valorfechaact = System.Convert.ToString(actyear) + "0" + System.Convert.ToString(actmonth);
        }

        actsecond = fecha.Second;

        string label;
        label = label1.Text;
        string at = "@";
        string filename = valorfechaact + ".csv";

        string ruta3 = System.IO.Path.Combine(at, label, filename); 
        if (Directory.Exists(label1.Text))
        {
            StreamWriter wr = new StreamWriter(ruta3, true);
            wr.WriteLine("1asd" + actsecond);
            wr.Close();
            wr.Dispose();
        }
        else
        {
            System.Console.WriteLine("no se puede escribir en el archivo");
            timer1.Stop();
        }
    }

Solution

  • You can write a Methode which try to open the File with a FileStream and return a boolean Flag

    A possible Solution is

    public static class FileInfoExtension
    {
        public static bool IsLocked(this FileInfo file)
        {
            FileStream stream = null;
            try
            {
                stream = file.Open(FileMode.Open, FileAccess.Read, FileShare.None);
            }
            catch (IOException)
            {
                return true;
            }
            finally
            {
                stream?.Close();
            }
            return false;
        }
    }
    

    Then you can use it

        var fileInfo = new FileInfo(ruta3);
        if (!fileInfo.IsLocked())
        {
           // do code
        }
    

    A very simple (and bad) Solution to wait is

        while (file.IsLocked())
        {
           Thread.Sleep(100);
        }
    

    General is your Code unclear and difficult to read.

    You have much redudant code and few variable are bad named. Maybe this Guidline can help you https://github.com/dennisdoomen/CSharpGuidelines

    Maybe a little bit clearer solution is

        private void timer1_Tick(object sender, EventArgs e)
        {
            var directory = label1.Text;
            if (!Directory.Exists(directory))
            {
                Console.WriteLine("no se puede escribir en el archivo");
                timer1.Stop();
                return;
            }
            var now = DateTime.Now;
            _valorfechaact = now.Month <= 9 ? $"{now.Year}00{now.Month}" : $"{now.Year}0{now.Month}";
            var fullname = Path.Combine("@", directory, $"{_valorfechaact}.csv");
            var fileInfo = new FileInfo(fullname);
            if (fileInfo.IsLocked())
            {
                Console.WriteLine($"The File {fullname} is locked!");
                return;
            }
            using (var wr = new StreamWriter(fullname, true))
            {
                wr.WriteLine("1asd" + now.Second);
            }
        }