【问题标题】:Why is this StreamReader only reading one line?为什么这个 StreamReader 只读取一行?
【发布时间】:2010-03-06 01:29:08
【问题描述】:

以下代码应该读取文件的每一行并对其进行操作。但是,它只读取第一行。如果没有 for 循环,它会读取整个文件。老实说,我不知道为什么它没有阅读全文。

StreamReader sr = new StreamReader(gridPath);

string line;
char[] lineCh;
char current;
int x, y;
bool north, east, south, west;

x = y = 0;

while ((line = sr.ReadLine()) != null)
{
    lineCh = line.ToCharArray();
    for (int i = 0; i < lineCh.Length; i++)
    {
        current = lineCh[i];
        north = CheckInput(current);
        current = lineCh[++i];
        east = CheckInput(current);
        current = lineCh[++i];
        south = CheckInput(current);
        current = lineCh[++i];
        west = CheckInput(current);
        i++; // Hop over space
        grid[x, y] = new GridSquare(north, east, south, west);
        x++; // Start next column
    }
    Console.WriteLine(line);
    y++;
}

如果没有 for 循环,以下工作并打印整个文件:

StreamReader sr = new StreamReader(gridPath);

string line;
char[] lineCh;
char current;
int x, y;
bool north, east, south, west;

x = y = 0;

while ((line = sr.ReadLine()) != null)
{
    lineCh = line.ToCharArray();

    Console.WriteLine(line);
    y++;
}

sr.Close();     

CheckInput如下:

private bool CheckInput(char c)
{
    switch (c)
    {
        case 'y':
            return true;
        case 'n':
            return false;
        default:
            return true;
    }
}

一个示例输入文件:

nyyn nyyy nyyy nyyy nyyy nnyy
yyyn yyyy yyyy yyyy yyyy ynny
yyyn yyyy yyyy yyyy ynyy nnnn
yyyn yyyy yyyy yyyy ynyy nnnn
yyyn yyyy yyyy yyyy yyyy nnyy
yynn yyny yyny yyny yyny ynny

【问题讨论】:

  • 顺便说一句,你不需要把字符串转成字符数组,String上面直接有索引器就可以用了
  • 可能是因为文件包含一行?
  • @tsv:你能告诉我们读取整个文件的代码吗? CheckInput 函数到底是什么?您是否在调用堆栈上方的某处捕获异常?
  • @tsv:假设 Visual Studio:转到 Debug -> Exceptions,在 Common Language Runtime Exceptions 旁边,单击 Throw 下的复选框。单击确定,然后在调试器中运行您的代码。
  • 与问题无关,但您应该使用带有StreamReader 的 using 语句以确保其正确处理

标签: c# streamreader


【解决方案1】:

您是否在 for 循环中遇到异常?您正在增加 i,也许在某些时候您试图错误地索引 lineCh

编辑:另一个错误索引的候选是grid 数组。看不到初始化代码,xy的值是读取文件后确定的。怎么初始化?

【讨论】:

  • 循环中没有异常。它读一整行很好;肯定它应该重置自己并阅读其他的罚款吗?
  • @tsv:你是如何检查并得出循环没有抛出异常并且它不是在其他地方捕获它的结论?
  • @Mehrdad 如果您使用示例输入计算循环,您应该会看到没有理由抛出异常。
  • @tsv:到目前为止,您已经查看了源代码,但看不出它不起作用的原因。您只是推测它不会引发异常,就像您推测代码运行正确(但它没有)一样。这不是调试的工作方式。您应该运行代码,一旦抛出异常就让调试器中断(在 VS 中按 Ctrl+Alt+E,检查 CLR 异常附近的抛出框)并确保没有抛出异常。如果它没有抛出,那么你应该进入代码并仔细检查它有什么问题。
【解决方案2】:

您正在修改循环体内的循环控制变量,这是您应该避免的事情,因为它会导致您的循环意外执行。

请显示您尝试处理的行的示例,我也许可以建议您更好地实现 for 循环。

您需要一次处理整行还是需要将其分成 4 个字符的块,处理这 4 个字符,然后移动到下一行?

您可以尝试更改处理线路的方式:

        while ((line = sr.ReadLine()) != null)
        {
            string[] segments = line.Split(' ');

            foreach(string segment in segments)
            {
                char[] arr = segment.ToCharArray();
                north = CheckInput(arr[0]);
                east = CheckInput(arr[1]);
                west = CheckInput(arr[2]);
                south = CheckInput(arr[3]);
                grid[x, y] = new GridSquare(north, east, south, west);
            }


            Console.WriteLine(line);
            y++;
        }

这里我根据空格拆分行,然后我可以通过拆分为字符数组并访问特定字符来对单个段进行操作。

这段代码还假设每个段总是有 4 个字符,这种情况总是这样吗?您还应该添加验证以确保该行是您所期望的。

【讨论】:

  • 现已添加输入示例。
  • 开箱即用的好想法。即使你可以离开 ToCharArray
  • 谢谢,为我提供了更简洁的代码,让我能够意识到实际的错误!
【解决方案3】:

您的代码会引发异常,因为您可以在任何这些行中获取数组边界:

current = lineCh[++i];

【讨论】:

    【解决方案4】:

    我认为你的问题可能是......

    for (int i = 0; i < lineCh.Length; i++)
    

    结合许多 ++i 语句。

    这是带有大量 cmets 的代码...假设每一行都是“1234”。

            StreamReader sr = new StreamReader(gridPath);
    
            string line;
            char[] lineCh;
            char current;
            int x, y;
            bool north, east, south, west;
    
            x = y = 0;
    
            while ((line = sr.ReadLine()) != null)
            // line is "yyyy"
            {
                lineCh = line.ToCharArray();
                // lineCh.Length is 4
                for (int i = 0; i < lineCh.Length; i++)
                {
                    current = lineCh[i]; // i is zero
                    north = CheckInput(current);
                    current = lineCh[++i]; // i is 1
                    east = CheckInput(current);
                    current = lineCh[++i]; // i is 2
                    south = CheckInput(current);
                    current = lineCh[++i];  // i is 3
                    west = CheckInput(current);
                    i++; // Hop over space // i is 4
                    grid[x, y] = new GridSquare(north, east, south, west);
                    // (true,true,true,true)
                    // So essentially the loop ends if there are four,
                    // or goes round again for multiples of 4 - of course,
                    // it will error if there is ever 3, or 5 or any other non multiple of 4
    
                    x++; // Start next column
                }
    

    【讨论】:

    • 为什么会出现这个问题? ++i 与 char 数组的结尾不同。大概 1 行中有 1 个以上的方格。
    • 它只需要使用我的“官方”输入,我现在已经给出了一个示例
    • 我不会在循环开始时再次递增吗?下一个循环将从 i==5 开始,应该是 4。
    • 这对我来说似乎是一个巨大的反模式。数据应该是序列化的,所以它是可读的。代码高度依赖数据格式,单个字符可能引发异常。
    【解决方案5】:

    在循环本身内增加循环变量是危险的。我建议为您的北、东等变量创建一个自定义类型,然后将每一行用到最后。或者甚至更好地返回下一个 GridSquare 对象。

    这可以通过返回 GridSquares 的迭代器的方法来完成:

    StreamReader sr = new StreamReader("input.txt");
    
    string line;
    char[] lineCh;
    char current;
    int x, y;
    bool north, east, south, west;
    
    x = y = 0;
    
    while ((line = sr.ReadLine()) != null)
    {
        foreach (var gs in GetGridSquares(line))
        {
            // grid[x, y] = gs;
        }
    
         Console.WriteLine(line);
         y++;
     }
    

    GetGridSquares 是:

     private IEnumerable<GridSquare> GetGridSquares(string line)
        {
            var splittedLine = line.Split(' ');
            foreach (var gsStr in splittedLine)
            {
                if (gsStr.Length != 4)
                {
                    continue;
                }
    
                yield return new GridSquare(gsStr[0], gsStr[1], gsStr[2], gsStr[3]);
            }
        }
    

    【讨论】:

      【解决方案6】:
      StreamReader sr = new StreamReader(gridPath);
      
      var line;       
      var y = 0;  
      
      while ((line = sr.ReadLine()) != null)
      {
          for(var i =0; i<line.length;i+=2)
          {
              grid[i,y]=new GridSquare(GetBits(line[i],i));
              grid[i+1,y]=new GridSquare(GetBits(line[i],i+1));
      
      
          }
          ++y;
      
      }
      
      bool [] GetBits(char bBytes, int n)
      {
          var returned = new bool[4];
          bBytes = bBytes << ((n%2)*4);
          for(var i =0; i < 4; ++i)
              returned[i]=(bBytes & (1<<i ) > 0;
      
      }
      

      【讨论】:

        【解决方案7】:

        我在清理代码后发现的实际答案是 x 从未被设置回零;我们永远不会移动到 grid[,] 的下一行。我意识到这很难从我的例子中解决,我在那里道歉。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-02-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-08-23
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多