C# 为什么StreamReader.ReadLine()为没有换行符的单行文件返回一个值?

C# 为什么StreamReader.ReadLine()为没有换行符的单行文件返回一个值?,c#,readline,streamwriter,C#,Readline,Streamwriter,我想把两个文本文件附加在一起 我有一个文件,末尾有一个回车换行符。观察28字节的文件A 这是文件中的一行\n 然后我有另一个文件,没有新行,它是相同的东西。观察文件B,它是26个字节 这是文件中的一行 我想将同一个文件附加到它自身(文件A到A,文件B到B),并比较字节计数 但是,在文件A上使用StreamReader.ReadLine()时,返回了一个值,但MSDN显示: 行号定义为后跟换行符(“\n”)、回车符(“\r”)或紧接换行符(“\r\n”)的回车符序列。返回的字符串不包含终止回车符或

我想把两个文本文件附加在一起

我有一个文件,末尾有一个回车换行符。观察28字节的文件A

这是文件中的一行\n

然后我有另一个文件,没有新行,它是相同的东西。观察文件B,它是26个字节

这是文件中的一行

我想将同一个文件附加到它自身(文件A到A,文件B到B),并比较字节计数

但是,在文件A上使用
StreamReader.ReadLine()
时,返回了一个值,但MSDN显示:

行号定义为后跟换行符(“\n”)、回车符(“\r”)或紧接换行符(“\r\n”)的回车符序列。返回的字符串不包含终止回车符或换行符。如果到达输入流的末尾,则返回值为null

但是,文件中没有crlf


如何安全地附加这些文件而不在末尾添加额外的换行符?例如,
StreamWriter.WriteLine()
将在文件A上添加一个额外的换行符,而我不希望它这样做。理想的方法是什么?

这实际上取决于实现的原因(为什么要逐行阅读并逐行写回?)您可以使用并输出存储的所有文本,这些方法之所以命名是因为它们附加了换行符

TextWriter.WriteLine方法(字符串)
将后跟行终止符的字符串写入文本流


您可以使用StreamWriter.Write而不是WriteLine来避免额外的crlf


至于ReadLine文档,我认为问题在于措辞不当。您当然不希望仅仅因为没有正式的行结束标志就丢弃文件的最后字节。

如果在流的末尾调用
ReadLine
,您只会得到
null
。否则,您将获取所有数据,直到
CRLF
或流结束

如果您试图进行逐字节复制(和比较),最好是读取字符(使用
StreamReader
/
StreamWriter
,就像您现在使用的那样)或字节(只使用
类)使用正常的
Read
Write
功能,而不是
ReadLine
WriteLine

您也可以使用
ReadToEnd
读取文件的全部内容,然后通过调用
write
(而不是
WriteLine
)进行写入,尽管如果文件很大,这并不实用

string data;

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

using(StreamWriter writer = new StreamWriter(path, true))
{
    writer.Write(data);
}

StreamReader和StreamWriter(源自TextReader和TextWriter)不适用于需要精确形式的二进制数据的情况。它们是由字节而不是文本或行组成的文件的高级抽象。事实上,不仅可以得到不同数量的换行符,而且根据环境的不同,您可能会写出一个与预期的CR/LF不同的行终止符

您应该只从一个流复制到另一个流。这其实很容易

var bytes = File.ReadAllBytes(pathIn);
var stream = File.Open(pathOut, FileMode.Append);
stream.Write(bytes, 0, bytes.Length);
stream.Close();
如果文件的大小可能较大,则应同时打开输入和输出文件,并使用固定大小的缓冲区一次复制一个块

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);
    }

}

另外值得注意的是,上面的代码可以替换为.NET 4中的新代码。

如果您只想附加整个文件,为什么您首先要考虑像“行”这样的虚构结构?使用
ReadToEnd
获取整个内容,或者一次读取一个块。当你打算逐字写回一些字符时,没有理由特别对待它们。我担心较大文件的内存使用。但是分块处理文件是有意义的。