【问题标题】:StreamReader read CRLFStreamReader 读取 CRLF
【发布时间】:2018-09-25 21:26:52
【问题描述】:

我正在验证来自我们客户的一些文件,这些文件必须满足特定的文件格式。每行有多个固定长度字段,以 511 个字符结束,其中字符 512 和 513 分别为 CR 和 LF。

我已经能够使用子字符串很容易地获取每个字段,但是我遇到了 StreamReader/ReadLine 定位第 512 个和第 513 个字符的问题。尝试使用子字符串定位这些字符时,我收到“System.ArgumentOutofRangeException”错误。

StreamReader file = new StreamReader(textBox2.Text);
while ((line = file.ReadLine()) != null)
{
    int lineLength = line.Length;
    string crlf = "";
    /*
    if (lineLength == 511)
    {
        crlf = line.Substring(511, 2);
    }
    */
 }

我已经注释掉了给出错误的部分。我有哪些选择来确认每行的结尾是 CRLF?

【问题讨论】:

  • What are my options to confirm the end of each line is CRLF? 不要使用ReadLine。使用ReadBlockReadToEnd
  • ReadLine 将返回没有换行符的行。
  • 为什么需要确认CR/LF?方法名称是ReadLine()。 Nomen est omen。如果不读一行,您认为ReadLine() 会做什么?行尾标有 CR/LF、LF 或“流结束”,还是您不同意?注意,我说它们是标记;它们不是文本行的一部分(文本行也可以像 EOF/EOS 一样结束),它们只是标记行的结尾。您真正想在这里实现什么目标?
  • @elgonzo 我知道 ReadLine() 会一直读取到行尾。文件格式要求规定每行的结尾需要是 CRLF。如果有人只使用 LF,那么我们就会遇到错误。
  • @Cody:是否允许使用多字节字符?例如,文件可以使用 UTF-8 编码,还是只需要 ASCII 字符?每行 513 个字节和每行 513 个字符之间存在差异。

标签: c# streamreader readline


【解决方案1】:

正如其他人在 cmets 中所说,您不能使用 ReadLine() 并期望在返回的字符串中找到 EOL 字符。现在,如果我理解正确,使用StreamReader,您可以执行以下操作:

using (var sr = new StreamReader(filePath))
{
    long position = 0;
    char[] buffer;
    while (sr.Peek() >= 0)
    {
        buffer = new char[513];
        sr.Read(buffer, 0, buffer.Length);
        if (buffer[511] == '\r' && buffer[512] == '\n')
        {
            position += 513;
            Console.WriteLine("CRLF");
        }
        else if (buffer[511] == '\r' || buffer[511] == '\n')
        {
            position += 512;
            sr.BaseStream.Seek(position, SeekOrigin.Begin);
            sr.DiscardBufferedData();
            Console.WriteLine("CR or LF");
        }
        else
        {
            Console.WriteLine("Something went wrong!");
            break;
        }
    }
}

这将一次读取 513 个字符的块并检查以下内容:

  • 如果最后两个字符是CRLF,那么我们就可以开始了,它将继续读取接下来的 513 个字符。

  • 1234563 " 是 512 个字符,而不是 513) 并继续阅读接下来的 513 个字符。
  • 如果以上测试都没有通过(即位置 511 的字符既不是CR 也不是LF),它将退出循环。 您可以根据自己的要求进行调整

如果您想以字符串的形式访问当前行,您可以使用以下方式轻松完成:

string line = new string(buffer, 0, 511);

【讨论】:

  • 仅供参考:sr.Read(buffer, 0, buffer.Length); 可以通过检查其返回值(=从流中读取的字符数)变得更加健壮,以防止由于文件不完整/截断而导致数据过早结束。
  • 除了测试 sr.Read 的返回值来检测不完整/截断的文件之外,在调用之前,可以将数组中的最后两个字符设置为零(或其他既不是 CR 也不是 LF 的字符) sr.Read 以可靠地检测是否已读取具有 CR/LF 的足够长度的行...
  • @elgonzo 你是对的。我在循环内移动了数组初始化。这样,如果长度不足,最后两个字符将是空值,这将导致它跳转到 else 分支。
  • @AhmedAbdelhameed 需要更多信息来说明.. 每行的长度可以选择为 509 或 513。两者都需要最后两个字符中的 CRLF。我猜要检查文件的长度并让它检查 line.length 是否返回 511,如果它返回 507,类似于上面,如果它返回 511 或 507 以外的任何内容,则会显示错误?
  • @Cody 您特别提到每行的固定长度为 511 个字符(不包括 EOL 字符),现在您正在更改要求。无论如何,在这种情况下,您可以检查位置 507 和 508 中的字符,如果找到 EOL,则相应地回溯。如果没有,您可以继续检查位置 511 和 512。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-03
  • 1970-01-01
  • 2013-08-07
  • 1970-01-01
相关资源
最近更新 更多