【问题标题】:Is there a way to read list & headers separately from CSV file without using any library in C#?有没有办法在不使用 C# 中的任何库的情况下从 CSV 文件中单独读取列表和标题?
【发布时间】:2021-12-09 10:36:33
【问题描述】:

所以我已经和我的导师一起制作了一个程序,它的全部内容是创建包含预制对象列表的 CSV 文件。 但由于我想继续进步,我想让它更加自动化。

问题是:我可以让我的程序在没有任何非 .NET 库的情况下创建新的对象列表时读取 CSV 文件的标题并向其附加值吗?

static void Main(string[] args)
        {

            /*
            1. In new files create two classes: House (properties: Id - int, Surface - int, Name - string, IsFlat - bool, Description - string), Human (Id - int, BirthDate - DateTime, Height - byte)
            In Houses description use some commas and watch out for them as it is a common csv separator and may cause you some trouble.
            2. Create two lists with at least 5 elements each, one with Houses and one with Humans
            3. Create two csv files and append to them the right text (check in Excel if it works)
            4. Try to extract the data from the files - two new variables that will have exactly the same as the ones created manually in the second step
            */

            List<House> houses = new List<House>() {
                new House(1, 100, "Stanowski", true, "House has two separate floors, upstairs there is a bedroom and a toilet, downstairs family has living room, kitchen and small garderobe"),
                new House(2, 240, "Borek", false, "This house has also two floors, small garden outside and inside there is 3 bedrooms, huge living room and nice - modern kitchen."),
                new House(3, 140, "Pol", true, "This house has bald floors"),
                new House(4, 280, "Boniek", false, "This house is simply - TOP"),
                new House(5, 50, "Lewandowski", true, "This house has golden balls around the living room")
            };
            List<Human> humans = new List<Human>() {
                new Human(1, new DateTime(1980, 7, 21), 185),
                new Human(2, new DateTime(1986, 4, 7), 176),
                new Human(3, new DateTime(2000, 8, 21), 200),
                new Human(4, new DateTime(2004, 2, 20), 145),
                new Human(5, new DateTime(1995, 11, 11), 198)
            };
            var strFilePath = @"C:\Users\Szymon\source\repos\ProjektCSV\ProjektCSV\";
            var humanFileName = "humans.csv";
            var houseFileName = "houses.csv";
            // Take list of properties from an object. - ekspression 'nameof'

            var houseColumnNamesString = CsvTools.GetClassPropertiesString<House>();

            var humanColumnNamesString = CsvTools.GetClassPropertiesString<Human>();

            
            var humanValues = new StringBuilder("");
            foreach (var human in humans)
            {
                humanValues.Append($"{human.Id};{human.BirthDay};{human.Height};\n");
            }

            
            using (StreamWriter fileHuman = new StreamWriter(strFilePath + humanFileName, false))
            {
                fileHuman.WriteLine(humanColumnNamesString);
                fileHuman.WriteLine(humanValues);
            }
            // Separate to different methods/classes 
            
            
            var readCSV = CsvTools.ReadCsv(strFilePath + houseFileName);
            Console.WriteLine(readCSV);
            
            
            //TODO
            // Make automatic reading of properties and it's values, like instead of house.ID in line 72
            using (var reader = new StringReader(manyLines))
            {
                string? item;
                do {
                    item = reader.ReadLine();
                    Console.WriteLine(item);
                    } while(item != null);
            }
            var houseValues = new StringBuilder("");
            foreach (var house in houses)
            {
                houseValues.Append($"{house.Id};{house.Name};{house.Surface};{house.IsFlat};{house.Description};\n");
            }
            using (StreamWriter file = new StreamWriter(strFilePath+houseFileName, false)) // true = add | false = overwrite
            { 
                file.WriteLine(houseColumnNamesString);
                file.WriteLine(houseValues);
            }
        } 

好的,这就是我需要的吗?

using(StreamReader file = new StreamReader(strFilePath + houseFileName))
            {
                string line;
                string headers = line.Take(1);
                while((line = file.ReadLine()) != null )
                {
                    var content = new List<House>(line);
                }    
            }

【问题讨论】:

  • 为什么不能?
  • 只为挑战
  • 那么你的问题是什么?怎么办?如何将类属性或属性映射到标题名称?
  • 问题是:我可以让我的程序在创建新的对象列表时读取 CSV 文件的标题并向其附加值吗?就像我手动创建了“House”列表一样。但我希望我的代码在从 CSV 文件中读取行时创建新列表,并且不需要任何额外的非微软库——比如 CSVHelper。
  • 文件只有行;正确的?所以第一行是标题。为什么你不能从文件中读取第一行并获取标题,然后对文件执行任何你想要的操作?

标签: c# .net csv


【解决方案1】:

您可以使用 C# 反射来遍历集合并构建您的数据。下面是 sn-p,它显示了如何实现这一点。它为您提供了方法,但我没有完全按照您希望字符串的方式构建:

var houses = new List<House>
                {
                    new House{Id = 1, Name = "Boulevard", Surface = "Plain"},
                    new House{Id = 2, Name = "Geneva", Surface = "Mat"},
                    new House{Id = 3, Name = "Lyncroft", Surface = "Carpet"}
                };

                var properties = Type.GetType("GenericRewriteDateIssueTest.House").GetProperties();
                var houseValues = new StringBuilder("");

                foreach (var house in houses)
                {
                    foreach (var prop in properties)
                    {
                        houseValues.Append($"{prop.GetValue(house)};");
                    }
                }

【讨论】:

  • 是的,所以这与我的代码在工作方式上相似,但我想从 CSV 文件中获取属性并创建全新的列表,而不是在您的情况下使用 prop.GetValue(house) - 这必须通过自动完成读线
  • 如果我理解你的问题是正确的,为什么不从标题中读取值并建立一个匿名类型列表。或者,使用类似这样的东西来设置值 house.GetType().GetProperty("").SetValue(house, );
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-03-24
  • 2021-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-01
  • 2021-11-04
相关资源
最近更新 更多