Runtime: Bug in File.WriteAllLines wherein it writes an extra newline

Created on 30 Jul 2019  路  7Comments  路  Source: dotnet/runtime

There is a bug in File.WriteAllLines wherein it writes an extra newline at the end.
It's easy to reproduce:

[TestMethod]
public void WriteAllLines()
{
            string noEmptyLineAtTheEnd = "Hello" + Environment.NewLine + "World";            

            File.WriteAllText("File1.txt", noEmptyLineAtTheEnd);            
            File.WriteAllLines("File2.txt", File.ReadAllLines("File1.txt"));

            Assert.AreEqual(File.ReadAllText("File1.txt").EndsWith(Environment.NewLine), File.ReadAllText("File2.txt").EndsWith(Environment.NewLine));
            // result:   Assert.AreEqual failed. Expected:<False>. Actual:<True>. 
}

A reasonable person could not be faulted for expecting that reading all lines and then writing all lines would produce a copy with the same number of lines, it doesn't.

area-System.IO

All 7 comments

That's expected behavior. It's always been that way. I don't think that should be considered a bug, and even if it is, it would be a massive breaking change to remove it.

The string[] array returned by ReadAllLines has no way to represent the difference between a new line at the end of file and no new line. Moreover, it also does not represent whether the new line characters were \n or \r\n. It is inherently lossy in nature and expected to behave that way.

@filipnavara that does not affect the code I posted because the first file does not end in an empty line, for the sake of clarity here is an example without ReadAllLines:

 [TestMethod]
 public void WriteAllLines()
 {
            string[] lines = new string[] { "Hello" , "World" };

            //Writes both lines and nothing else
            File.WriteAllText("File1.txt", lines[0] + Environment.NewLine + lines[1]); 
            //Writes both lines plus an extra line
            File.WriteAllLines("File2.txt", lines);

            Assert.AreEqual(File.ReadAllText("File1.txt").EndsWith(Environment.NewLine), File.ReadAllText("File2.txt").EndsWith(Environment.NewLine));
            // result:   Assert.AreEqual failed. Expected:<False>. Actual:<True>. 
}

You can also compare the length of the file content or open the files to observe the difference.

You are missing the point. The ReadAllLines API does not return the new line characters. For "a\nb" and "a\nb\n" it will return the same thing - new[] { "a", "b" }. There is no empty line involved (ie. no "a\nb\n\n"). Likewise, the WriteAllLines API inserts new line character(s) after each line.

A reasonable person could not be faulted for expecting that reading all lines and then writing all lines would produce a copy with the same number of lines, it doesn't.

...and it does! The number of new line characters may not be the same but the number of lines is. The last line is only counted once whether it ends with "\n" or not.

If you run the code you and open the files manually you will see the number of lines is different this issue has nothing to do with how ReadAllLinesworks.

You misunderstand how the lines are counted.

"a\nb" is two lines. "a\nb\n" is also two lines. "a\nb\n\n" are three lines.

In fact, to expand on that, "a\nb\n" is the preferred form for a good reason. If you write File.WriteAllLines("f.txt", new[] { "a", "b" }); File.AppendAllLines("f.txt", new[] { "c", "d" }); you'd probably expect the file to contain four lines. The new line between "b" and "c" has to be placed there at some point and it's natural to do it in the first call. You cannot reasonably do it in AppendAllLines because you'd have to read the file and write "\n" in the beginning if the file is non-empty. Naturally one would not expect Append method to read something and the file may not even be readable in the first place (device files, files with no permissions).

Was this page helpful?
0 / 5 - 0 ratings

Related issues

nalywa picture nalywa  路  3Comments

matty-hall picture matty-hall  路  3Comments

EgorBo picture EgorBo  路  3Comments

btecu picture btecu  路  3Comments

omajid picture omajid  路  3Comments