【问题标题】:C# reading a string from text file, splitting and putting into tabstringC#从文本文件中读取字符串,拆分并放入tabstring
【发布时间】:2020-08-19 23:44:21
【问题描述】:

我在编写一些简单的程序时遇到了困难,该程序将一些数据写入文本文件并稍后从该文件中读取它们。

我有一个将行写入 txt 文件的函数;每行包含姓名、姓氏和身份证号码。

下面我有一个从该文件中读取数据的函数。

我想将姓名、姓氏和身份证号码分开,所以下面的代码似乎是正确的,但在调试过程中,我收到了一条消息“发生了“发生‘System.NullReferenceException’类型的未处理异常”这一行: string[] tabstring = myString.Split(' ', ' ');.

我创建了包含 3 个元素的选项卡字符串 - 每个元素对应于行中的每个单词,即 tabstring[0]=Name 等等。

while 循环是对文本文件中的每一行执行此操作。但有些不对劲。

public void ReadFromFile()
        {
           FileStream fsListOfObjects = new FileStream("C:\\Users\\Dom\\Desktop\\ListOfObjects.txt", 
           FileMode.Open);
            StreamReader srListOfObjects = new StreamReader(fsListOfObjects);

            while (srListOfObjects.ReadLine() != null)
            {
                string myString= (srListOfObjects.ReadLine();
                Console.WriteLine(myString);
                **string[] tabstring = myString.Split(' ', ' ');**

                Name = tabstring[0];
                Surname = tabstring[1];
                Id= long.Parse(tabstring[2]);
                ClassName object= new ClassName(Name, Surname, Id);
                myList.Add(object);
            }
            srListOfObjects.Close();

            Console.ReadLine();
        }

这是文本文件的样子:

Ann Brown 1233456789
Bruce Willis 098987875
Bill Gates 789678678

等等……

对于所描述的问题,我将不胜感激。

【问题讨论】:

  • 准确地说:文本文件的每一行仅包含三个单词 Name (space between) Surname(spacebetween) Idnumber。
  • 注意:文件之间可能有制表符,这被认为是不同的字符。最好按原样发布文件内容
  • 没有文件没有任何标签,因为它是由函数创建的,每个单词之间只有一个空格,

标签: c# string list file split


【解决方案1】:

while (srListOfObjects.ReadLine().. 读取一行但不将其保存到变量中。 string myString= (srListOfObjects.ReadLine()) 读取另一行。

使用while (!srListOfObjects.EndOfStream) 检查流的结尾:StreamReader.EndOfStream Property

此外,检查拆分获得的字符串部分的正确数量是一个好主意 - 它可以防止诸如只有空格的行之类的事情。

像 StreamReaders 这样的东西需要调用 .Dispose() 来清除“非托管资源”——使用using 语句的简单方法是即使程序崩溃也能正常工作。

如果你将ReadFromFile 方法变成一个函数而不是一个void,那么你可以避免(没有双关语)对数据使用全局变量。全局变量不一定是问题,但通常最好避免它们。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace ConsoleApp1
{

    public class ClassName
    {
        public string Name { get; set; }
        public string Surname { get; set; }
        public long Id { get; set; }

    }

    class Program
    {
        public static List<ClassName> ReadFromFile(string fileName)
        {
            var result = new List<ClassName>();

            using (var sr = new StreamReader(fileName))
            {
                while (!sr.EndOfStream)
                {
                    string line = sr.ReadLine();
                    var parts = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                    if (parts.Count() == 3)
                    {
                        result.Add(new ClassName
                        {
                            Name = parts[0],
                            Surname = parts[1],
                            Id = long.Parse(parts[2])
                        });
                    }
                }
            }

            return result;

        }

        static void Main(string[] args)
        {
            string myFile = @"C:\temp\namesList.txt";
            var theList = ReadFromFile(myFile);

            foreach(var c in theList)
            {
                Console.WriteLine($"{c.Id} - {c.Surname}, {c.Name}");
            }

            Console.ReadLine();

        }
    }
}

输出:

1233456789 - 布朗,安
98987875 - 威利斯,布鲁斯
789678678 - 盖茨,比尔

【讨论】:

  • 这是理所当然的!写得很好且有用的代码。谢谢!
【解决方案2】:

你的问题在这里:

while (srListOfObjects.ReadLine() != null)
{
    string myString= (srListOfObjects.ReadLine();

您进入循环的条件是srListOfObjects.ReadLine() 返回的不是null,但随后您会立即读取新的行格式srListOfObjects 并将返回的引用存储在myString 中。这显然有两个问题:

  1. ReadLine 的第二次调用可以返回null,而您没有检查它是否是。您收到的错误是由于这个原因。
  2. 您正在丢失信息。在检查 while 条件时,您忽略了正在阅读的行。在您的程序崩溃或运行到最后(取决于输入文件的行数是偶数还是奇数)之前,您将只处理一半的数据。

更新: 每次迭代您应该只读取一行。一种方法是在进入循环之前声明和初始化myString,并在每次迭代时更新它:

var myString = srListOfObjects.ReadLine();

while (myString != null)
{
    //do your stuff
    myString = srListOfObjects.ReadLine();
}

【讨论】:

  • 是的!正是您的数字 2 准确地描述了我得到的结果 - 结果仅包含每隔一行 nad 然后程序崩溃。那么解决方案是什么?我是否应该通过“if”插入一些检查,检查该行是否实际上不为空,然后可以将其分配给字符串 my String ??
【解决方案3】:

https://docs.microsoft.com/en-us/dotnet/api/system.io.streamreader.readline?view=netcore-3.1

ReadLine() - 从当前流中读取一行字符并将数据作为字符串返回。

在您的代码中,您执行空值检查,然后再次调用 ReadLine。当您点击最后一行时,您将得到一个 NULL 字符串,并且拆分将因 NULL ref 而失败

【讨论】:

  • 正如@inbetween 指出的那样,您也在不处理第一行的情况下前进
  • 这一切都是真的,但是一旦循环到一个空行,它就应该停止,这意味着文件的末尾,因此字符串 myString= (srListOfObjects.ReadLine(); 不应该被执行,我说的对吗?
  • @kalka79 没有。您的文件只有一行。在 wile 循环条件中,您读取了一行,并且它不为空。你进入循环体。现在你读了一个新行并将它存储在myString 中。但是文件只有一行,因此新调用读取行返回nullmyString 因此是null。然后将myString 写入控制台。将null 写入控制台不会出错,它只会打印与Console.WriteLine() 相同的内容。然后,您尝试访问 myString 的实例成员,调用 .Split,您的程序就会崩溃。
  • 此文件包含几行而不是一行。但是 while 循环条件内的行应该是存储在 myString 中的同一行,对吗?
  • @kalka79 没关系,总行数为奇数会崩溃。如果总行数是偶数,它不会崩溃,更糟糕的是,你会认为它工作正常,但实际上并非如此;您正在丢失 50% 的尝试处理的信息。
猜你喜欢
  • 2016-04-30
  • 2023-04-08
  • 1970-01-01
  • 1970-01-01
  • 2012-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多