0

I have the following code in C# that writes an array of lines to a file. The difference between this and File.WriteAllLines(string, string[]); is that mine does not leave an extra newline at the end.

public static void WriteAllLinesCompact(string path, IEnumerable<string> contents)
{
    if (path == null)
        throw new ArgumentNullException("path");
    if (contents == null)
        throw new ArgumentNullException("contents");

    bool isFirst = true;
    using (FileStream stream = File.OpenWrite(path))
    using (StreamWriter writer = new StreamWriter(stream))
    {
        foreach (string line in contents)
        {
            if (isFirst)
            {
                writer.Write(line);
                isFirst = false;
                continue;
            }

            writer.Write("\r\n" + line);
        }
    }
}

The problem is that it does not terminate the file after the last line. For example, if the last line was "text = absolute", after replacing the last line with "tempor" and saving using the above method, the file's last line would be "tempor absolute" instead of just "tempor".

Please let me know if you need more information.

EDIT : I will try to explain more clearly what happens in the replace process.

Step 1 : Load any .txt file with File.ReadAllLines(string);
Step 2 : Replace the last line with one that's shorter than the previous one. For example, if the length of the last value was 10 chars, the new one should perhaps be 7 chars.
Step 3 : Save using the given method to the same file as before.

Hele
  • 1,558
  • 4
  • 23
  • 39
  • 1
    It is unclear what happens in this 'replace' process. Could you explain it better? – Steve Dec 06 '15 at 14:24
  • Yes, please give us two function calls of this method and what the file looks like before and after the execution of this method. I don't see any logic error in there, just be aware of that you use `File.OpenWrite()` whith which you will append the `contents` to the file. I don't see how the file's content should have changed from `text = absolute` to `tempor` when the last string in the `IEnumerable contents` is just `temport`. – Maximilian Gerhardt Dec 06 '15 at 14:24
  • You wrote this code to *intentionally* never end the last line with "\r\n". Pretty unclear why you are mystified by what you intended to do. Don't copy/paste code you don't understand, I guess. Get rid of isFirst and just use WriteLine(). – Hans Passant Dec 06 '15 at 14:28
  • @Steve Try the steps I have edited. You will see clearly what I mean. – Hele Dec 06 '15 at 14:28
  • @HansPassant I do not want a newline at the end. Why cant I just end the file with a non-newline character? P.S. This is not copy pasted code. – Hele Dec 06 '15 at 14:29
  • 1
    My crystal ball says that you'll be happy when you use File.Delete(path) first. So the content of an existing file cannot produce a mix of new and old text. Or just plain use the StreamWriter(string) constructor so it always overwrites the file completely. – Hans Passant Dec 06 '15 at 14:34
  • @Steve I open the file with notepad++. – Hele Dec 06 '15 at 14:35
  • @HansPassant I would like to avoid the extra overhead. More importantly, I am curious to know *why* this happens. – Hele Dec 06 '15 at 14:35
  • 1
    While writing to a stream your only running over the content in the memory area that you are writing to. the leftovers will remain unless you delete them using File.Delete(path) first or end the file on your own which can result in unexpected outcomes since it leaves a trail of junk at the end of the file. – Ron.B.I Dec 06 '15 at 14:37
  • 1
    Just read the MSDN article for File.OpenWrite(), it specifically mentions this behavior. – Hans Passant Dec 06 '15 at 14:37
  • I was wrong, I wrote the output on a different file, if I write on the same file the problem occurs as explained – Steve Dec 06 '15 at 14:39
  • @HansPassant That makes sense now. Can I somehow end the file using the stream itself? – Hele Dec 06 '15 at 14:41
  • 1
    I honestly don't see the exact point of so many comments, because the problem/solution seem clear. If you are providing the right inputs via `contents` (what we don't know because you are not showing this code), just make sure that the code writing to the file works for sure. Just need two changes: remove the FileStream part and instantiate the FileWriter directly from the path + rely on `writer.WriteLine()` and forget about including new lines (or use `Environment.NewLine`, rather than "\r\n"). After these changes, I am sure that the code will work exactly as expected. – varocarbas Dec 06 '15 at 14:47
  • @varocarbas Your solution works. I do not want a newline at the end as I feel it makes the file look ugly, almost like something was meant to be there but isn't. Could you post your comment as an answer? – Hele Dec 06 '15 at 14:50
  • I usually prefer to let the comment as a comment, but I guess that here it is not clear. I will do it right now. – varocarbas Dec 06 '15 at 14:53
  • 1
    Sideways related question about [why text files usually end with a newline](http://stackoverflow.com/questions/729692/why-should-text-files-end-with-a-newline). This does not change the fact that you should be able to write text files that don't end in a newline. – joranvar Dec 06 '15 at 15:12

1 Answers1

2

As suggested via comments, the best solution in this kind of situations is keeping it simple and relying on a for-sure-working solution. For example:

bool isFirst = true;

using (StreamWriter writer = new StreamWriter(path))
{
    foreach (string line in contents)
    {
        if (isFirst)
        {
            writer.Write(line);
            isFirst = false;
            continue;
        }

        writer.Write(Environment.NewLine + line);
    }
}

Personally, I would prefer to use writer.WriteLine, but it would go against the OP's requirement of not including a final new line.

varocarbas
  • 12,354
  • 4
  • 26
  • 37