views:

78

answers:

4

I want to append two text files together.

I have one file with a carriage return line feed at the end. Observe file A which is 28 bytes.

this is a line in the file\n

then I have another file which is the same thing without the new line. Observe file B which is 26 bytes.

this is a line in the file

I want to append the same file to itself (file A to A, and file B to B) and compare the byte counts.

However, when using StreamReader.ReadLine() on file A, I get a value returned but MSDN says:

A line is defined as a sequence of characters followed by a line feed ("\n"), a carriage return ("\r") or a carriage return immediately followed by a line feed ("\r\n"). The string that is returned does not contain the terminating carriage return or line feed. The returned value is null if the end of the input stream is reached.

However, there is no crlf in the file.

How can I safely append these files without adding an extra line break at the end? For example, StreamWriter.WriteLine() will put an extra line break on file A when I don't want it to. What would be an ideal approach?

A: 

Well it really depends on the reasons for your implementation (Why are you reading it by line and writing it back line by line?) You could just use StreamWriter.Write(string) and output all the text you have stored, the WriteLine() methods are named as such because they append a newline.

TextWriter.WriteLine Method (String)
Writes a string followed by a line terminator to the text stream.

Quintin Robinson
+1  A: 

You can use StreamWriter.Write instead of WriteLine to avoid the extra crlf.

As to the ReadLine docs, I beleive the problem is a poorly worded explanation. You certainly wouldn't want the last bytes of a file discarded just because there is no formal line ending flag.

Ray
A: 

You'll only get null if you call ReadLine at the end of the stream. Otherwise, you'll get all data up until either a CRLF or the end of the stream.

If you're trying to do a byte-for-byte duplication (and comparison), you're better off reading either characters (using StreamReader/StreamWriter as you're using now) or bytes (using just using the Stream class) using the normal Read and Write functions rather than ReadLine and WriteLine.

You could also just read the entire contents of the file using ReadToEnd then write it by calling Write (not WriteLine), though this isn't practical if the file is large.

string data;

using(StreamReader reader = new StreamReader(path))
{
    data = reader.ReadToEnd();
}

using(StreamWriter writer = new StreamWriter(path, true))
{
    writer.Write(data);
}
Adam Robinson
+1  A: 

StreamReader and StreamWriter (which derive from TextReader and TextWriter) are not suitable for situations requiring an exact form of binary data. They are high level abstractions of a file which consists of bytes, not text or lines. In fact, not only could you wind up with different number of newlines, but depending on the environment you might write out a line terminator other than the expected CR/LF.

You should instead just copy from one stream to another. This is quite easy actually.

var bytes = File.ReadAllBytes(pathIn);
var stream = File.Open(pathOut, FileMode.Append);
stream.Write(bytes, 0, bytes.Length);
stream.Close();

If the size of the file is potentially large, you should open both the input and output file at the same time and use a fixed-sized buffer to copy a block at a time.

using (var streamIn = File.Open(pathIn, FileMode.Read))
using (var streamOut = File.Open(pathOut, FileMode.Append)) {

    var bytes = new byte[BLOCK_SIZE];

    int count;
    while ((count=streamIn.Read(bytes, 0, bytes.Length)) > 0) {
        streamOut.Write(bytes, 0, count);
    }

}

Also worth noting is that the above code could be replaced by Stream.CopyTo which is new in .NET 4.

Josh Einstein