Reputation: 31
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
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
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