none
C# File.WriteAllLines(string path, string[] array) writes an extra empty line?

    Question

  • I am using File.WriteAllLines("C:\file.txt", string[]) to write out an array of strings to a file however am encountering a problem because it appends an extra return character
    at the end, so using File.ReadAllLines(...) to get the array back produces an array with an extra string inside.

    I have double checked everything, my array only contains 2 strings however opening the output file with a text editor or File.ReadAllLines clearly shows an extra line at the end, is there a work around for this problem?
    Monday, June 08, 2009 11:10 AM

Answers

  • Here's the implementation of WriteAllLines():

        using (StreamWriter writer = new StreamWriter(path, false, encoding))
        {
            foreach (string str in contents)
            {
                writer.WriteLine(str);
            }
        }

    So each line written will have a linefeed following it. This is what I'd expect it to do - I wouldn't expect the last line to be different from all the others.

    If you want special behaviour, it's very easy:

        using (StreamWriter writer = new StreamWriter(path, false, encoding))
        {
            for (int i = 0; i < contents.Length; ++i)
            {
                 if (i == contents.Length-1)
                      writer.Write(str);
                 else
                      writer.WriteLine(str);
            }
        }
    • Marked as answer by Figo Fei Monday, June 15, 2009 2:54 AM
    Monday, June 08, 2009 12:33 PM
  • "File.ReadAllLines clearly shows an extra line at the end"

    That would show a string length of 3 rather than 2, wouldn't it?

    The code I posted does what would normally be expected when reading and writing text files.  I take from the OP's post that he is getting something different.
    • Marked as answer by Figo Fei Monday, June 15, 2009 2:54 AM
    Monday, June 08, 2009 3:15 PM
  • string[] lines = File.ReadAllLines(@"C:\myFile.txt");
    for (int i = 0; i < lines.Length - 1; i ++)
    {

    }
    John Grove - TFD Group, Senior Software Engineer, EI Division, http://www.tfdg.com
    • Marked as answer by Figo Fei Monday, June 15, 2009 2:54 AM
    Monday, June 08, 2009 4:14 PM
  • Or:

    string line;
    using (StreamReader sr = new StreamReader(@"C:\myfile.Txt"))
    {
        do
        {
            line = sr.ReadLine();
        } while (!sr.EndOfStream);
    }
    John Grove - TFD Group, Senior Software Engineer, EI Division, http://www.tfdg.com
    • Marked as answer by Figo Fei Monday, June 15, 2009 2:54 AM
    Monday, June 08, 2009 4:18 PM

All replies

  • Here's the implementation of WriteAllLines():

        using (StreamWriter writer = new StreamWriter(path, false, encoding))
        {
            foreach (string str in contents)
            {
                writer.WriteLine(str);
            }
        }

    So each line written will have a linefeed following it. This is what I'd expect it to do - I wouldn't expect the last line to be different from all the others.

    If you want special behaviour, it's very easy:

        using (StreamWriter writer = new StreamWriter(path, false, encoding))
        {
            for (int i = 0; i < contents.Length; ++i)
            {
                 if (i == contents.Length-1)
                      writer.Write(str);
                 else
                      writer.WriteLine(str);
            }
        }
    • Marked as answer by Figo Fei Monday, June 15, 2009 2:54 AM
    Monday, June 08, 2009 12:33 PM
  • I can't repro:

        private void button1_Click(object sender, EventArgs e)
        {
          String[] s = { "This is string 1.", "This is string 2." };
          WriteStrings(s);
          File.WriteAllLines("Text.txt",s);
          Array.Clear(s, 0, s.Length);
          s = File.ReadAllLines("Text.txt");
          WriteStrings(s);
        }
        void WriteStrings(string[] s)
        {
          foreach (string str in s) Console.WriteLine(str);
          Console.WriteLine(s.Length);
        }

    This is string 1.
    This is string 2.
    2
    This is string 1.
    This is string 2.
    2

    Monday, June 08, 2009 1:42 PM
  • I think he's worried about the linefeed on the last line.
    Monday, June 08, 2009 2:48 PM
  • "File.ReadAllLines clearly shows an extra line at the end"

    That would show a string length of 3 rather than 2, wouldn't it?

    The code I posted does what would normally be expected when reading and writing text files.  I take from the OP's post that he is getting something different.
    • Marked as answer by Figo Fei Monday, June 15, 2009 2:54 AM
    Monday, June 08, 2009 3:15 PM
  • Hmm good point. But that's impossible, given what Reflector shows as the implementation...
    Monday, June 08, 2009 3:31 PM
  • string[] lines = File.ReadAllLines(@"C:\myFile.txt");
    for (int i = 0; i < lines.Length - 1; i ++)
    {

    }
    John Grove - TFD Group, Senior Software Engineer, EI Division, http://www.tfdg.com
    • Marked as answer by Figo Fei Monday, June 15, 2009 2:54 AM
    Monday, June 08, 2009 4:14 PM
  • Or:

    string line;
    using (StreamReader sr = new StreamReader(@"C:\myfile.Txt"))
    {
        do
        {
            line = sr.ReadLine();
        } while (!sr.EndOfStream);
    }
    John Grove - TFD Group, Senior Software Engineer, EI Division, http://www.tfdg.com
    • Marked as answer by Figo Fei Monday, June 15, 2009 2:54 AM
    Monday, June 08, 2009 4:18 PM
  • Thanks for the replies, I understand that I can easily use a stream reader or writer to access the text file but I'm trying to understand why Microsoft decided to have an extra line feed at the end of the WriteAllLines method for writing an array of strings to a text file. It makes no sense why they have a line feed for the last line since there is no more text in the array, the solutions listed here will work.
    Monday, June 08, 2009 9:43 PM
  • Where is this extra linefeed?  DOS uses carriage return, linefeed as an end of line marker.
    Monday, June 08, 2009 9:55 PM
  • Thanks for the replies, I understand that I can easily use a stream reader or writer to access the text file but I'm trying to understand why Microsoft decided to have an extra line feed at the end of the WriteAllLines method for writing an array of strings to a text file. It makes no sense why they have a line feed for the last line since there is no more text in the array, the solutions listed here will work.
    Well, because they call WriteLine() for ALL the lines, they called it WriteAllLines().

    I'm struggling to think of a reason why they wouldn't do it that way...
    Monday, June 08, 2009 11:10 PM
  • A simple explanation is that the first string in the string array already contains a "\r\n".  Perhaps you read it with ReadAllText().
    Hans Passant.
    Tuesday, June 09, 2009 5:08 AM
    Moderator
  • Here is an example to explain:

    string[] example = new string[] {"test", "A", "B", "C"};
    File.WriteAllLines("C:\test.txt", example);

    //the file output is below:
    **************************************
    test
    A
    B
    C

    **************************************

    Now there is an extra line at the end after the last array sequence "C".
    I'm wondering why it isn't simply:

    **************************************
    test
    A
    B
    C
    **************************************

    This seems more logical since if the user needs an extra line at the end they could simply add the escape sequence \n\r and have it added, however if a user wants to write a file like the second one shown it has to iterate through using a for loop and handle the last line separately.
    Tuesday, June 09, 2009 6:21 AM
  • There appears to be a bug in the code that writes the stars.  No special handling is required for the final "\r\n", it is consumed by the ReadLine() method, just like all the other ones.  It belongs to the last line, it doesn't start a new line.

    Hans Passant.
    Tuesday, June 09, 2009 6:28 AM
    Moderator
  • Change your culture to one where Environment.NewLine = carriage return alone without the line feed.
    Tuesday, June 09, 2009 7:08 AM
  • Environment.NewLine is not culture-dependent, it is platform-dependent.
    Tuesday, June 09, 2009 8:23 AM
  • Here is an example to explain:

    string[] example = new string[] {"test", "A", "B", "C"};
    File.WriteAllLines("C:\test.txt", example);

    //the file output is below:
    **************************************
    test
    A
    B
    C

    **************************************

    Now there is an extra line at the end after the last array sequence "C".
    I'm wondering why it isn't simply:

    **************************************
    test
    A
    B
    C
    **************************************

    This seems more logical since if the user needs an extra line at the end they could simply add the escape sequence \n\r and have it added, however if a user wants to write a file like the second one shown it has to iterate through using a for loop and handle the last line separately.

    Please show us the test code that produces that output!
    Tuesday, June 09, 2009 8:27 AM
  • Environment.NewLine is not culture-dependent, it is platform-dependent.

    There must be someway to change it from Chr(13) + Chr(10) to Chr(13) alone on an Intel platform.  This whole thread is academic, since Chr(13) + Chr(10) has been the DOS line marker for approximately 30 years.  The chances of the OP getting it changed is not zero, but the probabilities are quite low.  Everyone has their windmills.
    Tuesday, June 09, 2009 9:00 AM
  • Well, according to Reflector the implementation of Environment.NewLine is:

    public static string get_NewLine()
    {
        return "\r\n";
    }
    Tuesday, June 09, 2009 9:11 AM
  • You can set the newline string for the StreamWriter to anything you wish. 
    Tuesday, June 09, 2009 9:37 AM
  • You can, but not if you're calling File.WriteAllLines(), so that's no use.
    Tuesday, June 09, 2009 9:43 AM
  • No stars are being produced by the output, I used that simply to represent the beginning and ending of the file, the lines between the stars is what appears inside the text file. In the second file output example you can see that an extra line feed is added because WriteAllLines writes each string array element followed by the new line. What I am wondering is why the last new line is necessary it is much easier to implement the last line by adding the string "\n\r" to the array, however if the user does not want an extra line at the end then it requires more code to create the file.

    The code compatibility is the issue that has me confused not why the output is a certain way.
    Wednesday, June 10, 2009 5:56 AM
  • It's because a "line" is defined as a sequence of characters terminated by a newline.
    And WriteAllLines(), as it's name implies, calls WriteLine() for ALL lines, as I already pointed out. It's consistent.
    Wednesday, June 10, 2009 8:41 AM