3

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.

BradleyDotNET
  • 60,462
  • 10
  • 96
  • 117
Mtlca401
  • 31
  • 1
  • 2
  • This looks like a permissioning issue. – SLaks Feb 26 '10 at 04:13
  • Never mind. Windows Explorer stills shows a locked icon, but the rest of my code was wrong. sorry. but thanks for the using tip. I have to look more into the readBlock. – Mtlca401 Feb 26 '10 at 04:33

2 Answers2

3

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");
SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • I'd also suggest that if you're copying a file yourself, doing so in fixed size blocks (4K, 8K?) is more efficient than line-by-line. – Andrew Feb 26 '10 at 04:06
  • I tried this, but it still gives the same results. What's happening is, I have windows 7 by the way, as soon as the program hits "File.Move" I get a lock image on the icon of the file. After this, I cannot write anything to the file. It looks like it writes, but the file is not changed when I open it through windows explorer. I get no errors saying file in use either. – Mtlca401 Feb 26 '10 at 04:12
  • Your answer helped me, upvoted, Thanks!! I added an answer that I hope will help people who are having essentially the same issue except with XmlTextReaders. I wasn't recalling the underlying StreamReader that needs to be closed. – Developer63 May 10 '19 at 18:37
0

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.

Developer63
  • 640
  • 7
  • 19