Mtlca401
Mtlca401

Reputation: 31

File locks when using file.move in c#...how can I stop or fix this

Code:

        String tempFile = Path.GetTempFileName(), read = "";
        TextReader pending = new StreamReader("c:\\pending.txt");
        TextWriter temp = new StreamWriter(tempFile);

        read = pending.ReadLine();

        while ((read = pending.ReadLine()) != null)
        {
            temp.WriteLine(read);
        }

        pending.Close();
        temp.Close();

        File.Delete("c:\\pending.txt");
        File.Move(tempFile, "c:\\pending.txt");

The pending.txt file is created when the program starts if it doesn't exist. This code deletes the first line of the file. When I debug the code, I notice that the

        File.Move(tempFile, "c:\\pending.txt");

locks the file and I cannot write to it anymore.

Upvotes: 3

Views: 4276

Answers (2)

Developer63
Developer63

Reputation: 710

I had a similar situation with XML results files, produced by the xUnit console runner. I'm adding it as an answer here in case it helps others find the cause/solution when the StreamReader is in the form of an XmlTextReader, which is built on top of Stream and TextReader, and also can place locks on the underlying file that make subsequent Move and Delete operations fail if the underlying stream and reader are not closed and disposed of immediately when done with reads.

   public void ReadResultsXmlFile(string testResultsXmlFile)
{
    MyXmlTextReader = new XmlTextReader(testResultsXmlFile);
    testResultXmlDocument = new XmlDocument();
    testResultXmlDocument.Load(MyXmlTextReader); 
    XmlNode xnAssembliesHeader = testResultXmlDocument.SelectSingleNode("/assemblies");
    XmlNodeList xnAssemblyList = testResultXmlDocument.SelectNodes("/assemblies/assembly");
    foreach (XmlNode assembly in xnAssemblyList)
    {
        XmlNodeList xnTestList = testResultXmlDocument.SelectNodes(
            "/assemblies/assembly/collection/test");
        foreach (XmlNode test in xnTestList)
        {
            TestName = test.Attributes.GetNamedItem("name").Value;
            TestDuration = test.Attributes.GetNamedItem("time").Value;
            PassOrFail = test.Attributes.GetNamedItem("result").Value;
        }
    }
}

Of course, it's obvious in hindsight that I failed to close the XmlTextReader that includes an underlying StreamReader, and that this was leaving locks on the XML results files.

The fixed code looks like this:

   public void ReadResultsXmlFile(string testResultsXmlFile)
    {
        using (MyXmlTextReader = new XmlTextReader(testResultsXmlFile))
        {
            testResultXmlDocument = new XmlDocument();
            testResultXmlDocument.Load(MyXmlTextReader); // suppose that myXmlString contains "<Names>...</Names>"
            XmlNode xnAssembliesHeader = testResultXmlDocument.SelectSingleNode("/assemblies");
            XmlNodeList xnAssemblyList = testResultXmlDocument.SelectNodes("/assemblies/assembly");
            foreach (XmlNode assembly in xnAssemblyList)
            {
                XmlNodeList xnTestList = testResultXmlDocument.SelectNodes(
                    "/assemblies/assembly/collection/test");
                foreach (XmlNode test in xnTestList)
                {
                    TestName = test.Attributes.GetNamedItem("name").Value;
                    TestDuration = test.Attributes.GetNamedItem("time").Value;
                    PassOrFail = test.Attributes.GetNamedItem("result").Value;
                }
            }
        }
    }

... and the problem with locked files for subsequent Move and Delete operations went away. The key lines of course, being

using (MyXmlTextReader = new XmlTextReader(testResultsXmlFile))
{
// Do stuff inside "using...  block
} // At close of "using" block, objects in using get Released...

For what it's worth, the app is a test runner that runs Selenium-based automated web tests, using the xUnit console test runner, and telling xUnit console runner to create XML results files, via a command-line option. SpecFlow is also involved, on top of the xUnit test runner layer, but xUnit results files are what is being read. After the test execution, I wanted to move the XML results files into date-based archive folders, and that File.Move() operation was failing due to locks on the xUnit results files, as a result of the code without the using block.

Upvotes: 0

SLaks
SLaks

Reputation: 887365

You should close your StreamReader and StreamWriter in using statements, like this:

String tempFile = Path.GetTempFileName(), read = "";
using(TextReader pending = new StreamReader("c:\\pending.txt"))
using(TextWriter temp = new StreamWriter(tempFile))
{

    read = pending.ReadLine();

    while ((read = pending.ReadLine()) != null)
    {
        temp.WriteLine(read);
    }
}

File.Delete(@"c:\pending.txt");
File.Move(tempFile, @"c:\pending.txt");

Upvotes: 3

Related Questions