【问题标题】:Reading CSV file and converted to transposed table读取 CSV 文件并转换为转置表
【发布时间】:2018-07-12 13:29:46
【问题描述】:

我需要读取一个 CSV 文件(用“;”分隔),并且应该创建一个包含转置(旋转)表的新文件:

我的输入文件:

  • 该工具应能够从用户那里接收表格的文件名并加载表格以转置内容。
  • 该工具应能够以输入文件的文件名将转置表保存在一个新文件中,并以“转置”(“filename_transposed.csv”)扩展。

我的代码

public void ReadCsv()
            {
                // open the file "data.csv" which is a CSV file with headers
                using (CsvReader csv = new CsvReader(
                                       new StreamReader("C:\\Users\\moki\\Downloads\\Input.csv"), true))
                {
                    int fieldCount = csv.FieldCount;

                    string[] headers = csv.GetFieldHeaders();
                    while (csv.ReadNextRecord())
                    {
                        for (int i = 0; i < fieldCount; i++)
                            Console.WriteLine(string.Format("{0}\n{1}",
                                          headers[0], csv[i]) );

                    }
                }
Console.ReadLine();

我的结果

【问题讨论】:

  • 您是否要求为您开发它?
  • 是的,我需要在我的代码中添加什么
  • 你为此付了多少钱?
  • 想一想完成它需要执行的逻辑步骤。然后把每一步都变成代码。
  • 你想把行变成列......一个简单的开始方法是创建一堆List&lt;string&gt;;每行一个。然后每个列表将代表一列数据。

标签: c# .net visual-studio csv


【解决方案1】:

既然我们正在提供答案...

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

namespace _51306985
{
    class Program
    {
        static List<List<string>> listOfList = new List<List<string>>();
        static int longestCol = 0;
        static void Main(string[] args)
        {
            FillTheList("M:\\StackOverflowQuestionsAndAnswers\\51306985\\testdata.csv");
            PadTheList();
            SpitItBackOut();
            SpitItOutToAFile("M:\\StackOverflowQuestionsAndAnswers\\51306985\\testdata.csv");
            Console.ReadLine();
        }

        private static void SpitItOutToAFile(string v)
        {
            string newPath = $"{System.IO.Path.GetDirectoryName(v)}\\{System.IO.Path.GetFileNameWithoutExtension(v)}_Rotated{System.IO.Path.GetExtension(v)}";
            using (System.IO.StreamWriter sw = new System.IO.StreamWriter(newPath))
            {
                for (int i = 0; i < longestCol; i++)
                {
                    string lineToWrite = string.Empty;
                    for (int b = 0; b < listOfList.Count; b++)
                    {
                        lineToWrite += $"{listOfList[b][i]},";
                    }
                    lineToWrite = lineToWrite.Substring(0, lineToWrite.Length - 1);//remove the hanging comma
                    if (lineToWrite != "")
                    {
                        sw.WriteLine(lineToWrite);
                    }

                }
            }
        }

        private static void SpitItBackOut()
        {
            for (int i = 0; i < longestCol; i++)
            {
                string lineToWrite = string.Empty;
                for (int b = 0; b < listOfList.Count; b++)
                {
                    lineToWrite += $"{listOfList[b][i]},";
                }
                lineToWrite = lineToWrite.Substring(0, lineToWrite.Length - 1);//remove the hanging comma
                if (lineToWrite != "")
                {
                    Console.WriteLine(lineToWrite);
                }

            }
        }

        private static void PadTheList()
        {
            foreach (List<string> item in listOfList)
            {
                while (item.Count < longestCol)
                {
                    item.Add("");
                }
            }
        }

        private static void FillTheList(string v)
        {
            using (System.IO.StreamReader sr = new System.IO.StreamReader(v))
            {
                string currentLine = string.Empty;
                while ((currentLine = sr.ReadLine()) != null)
                {
                    listOfList.Add(currentLine.Split(',').ToList());
                    if (listOfList.Last().Count > longestCol)
                    {
                        longestCol = listOfList.Last().Count;
                    }
                }
            }
        }
    }
}

输入数据

a1,b1,c1,d1,e1
a2,b2,c2,d2,e2
a3,b3,c3,d3,e3
a4,b4,c4,d4,e4
a5,b5,c5,d5,e5
a6,b6
a7,b7,c7,d7
a8,b8,c8

输出

a1,a2,a3,a4,a5,a6,a7,a8
b1,b2,b3,b4,b5,b6,b7,b8
c1,c2,c3,c4,c5,,c7,c8
d1,d2,d3,d4,d5,,d7,
e1,e2,e3,e4,e5,,,

【讨论】:

  • 感谢您的解决方案,但输出也需要为 table csv
  • @MokiNex,不确定你的意思……在我的 sn-p 中,输入和输出是 csv 表。该代码甚至解释了不完整的传入行。
  • 我的意思是 csv 文件没有输出路径
  • @MokiNex,那里...我添加了一个方法来做到这一点SpitItOutToAFile
【解决方案2】:

以防万一,如果有人想知道如何使用Cinchoo ETL 来做几行代码,

string csv = @"A1;B1;C1;D1;E1
A2;B2;C2;D2;E2
A3;B3;C3;D3;E3
A4;B4;C4;D4;E4
A5;B5;C5;D5;E5
";

StringBuilder sb = new StringBuilder();
using (var p = ChoCSVReader.LoadText(csv)
    .WithDelimiter(";")
    .ThrowAndStopOnMissingField(false)
    )
{
    using (var w = new ChoCSVWriter(sb)
        .WithDelimiter(";")
        )
    {
        w.Write(p.Cast<ChoDynamicObject>().Transpose(false));
    }
}

Console.WriteLine(sb.ToString());

输出:

A1;A2;A3;A4;A5
B1;B2;B3;B4;B5
C1;C2;C3;C4;C5
D1;D2;D3;D4;D5
E1;E2;E3;E4;E5

【讨论】:

    【解决方案3】:

    肯定有一种更有效的方法,但我认为这是一种易于理解的方法:

    1.) 将数据放入数据表中,例如喜欢:

    StreamReader sr1 = new StreamReader("C:\\Users\\moki\\Downloads\\Input.csv");  //create the streamreader to read the input .csv
    DataTable mydata = new DataTable();  //create an empty DataTable.....
    string[] arr;                        //....and an array in which you will store the elemnets of each line
    int i = 0;                           //just a variable to help counting where you are in your data
    bool mydatasetup = false;            //a variable to check in the loop if you already added the necessary number of columns to the datatable 
    
            using (sr1)
            {
                while (sr1.EndOfStream == false)    //read the whole file
                {
                    string line = sr1.ReadLine();    //get a line from the file
    
                    if (line != null && line != String.Empty) //check if there is content in the line
                    {
                         arr = line.Split(';');    //split the line at each ";" and put the elements in the array
    
                        if(mydatasetup == false)   //after reading the first line add as many columns to your datatable as you will need..... 
                        {
                            for (int u = 0; u < arr.Length; u++)
                            {
                                mydata.Columns.Add();
                            }
                            mydatasetup = true; //...but only do this once (otherwise you wil have an unneccessary big datatable
                        } 
    
                         mydata.Rows.Add();   //add a row in you datatable in which you will store the data of the line
    
                         for (int j = 0; j < arr.Length; j++)    //go throught each element in your array and put it into your datatable
                            {
                                if (arr[j] != "")
                                {
                                    mydata.Rows[i][j] = arr[j];
                                }
                            }
                         i = i + 1; //increase the counter so that the program knows it has to fill the data from the next line into the next row of the datatable
                      }
                  }
               }
    

    2.) 然后您可以遍历数据表的列并将每一行的内容添加到 Stringbuilder(您可以在其中转置数据),然后将其保存为 .csv:

    StringBuilder sb = new StringBuilder();  //create a stringbuilder
    
          for (int u = 0; u < mydata.Columns.Count; u++)   //loop through the COLUMNS of your datatable....
                {
                for (int i = 0; i < mydata.Rows.Count; i++)  //....but for each column go through each row in the datatable first  
                        {
                            sb.Append(mydata.Rows[i][u].ToString()); // and add the elements to the stringbuilder - here the transposing is actually done
    
                            if (i < mydata.Rows.Count - 1)   //add a deliminator after each element because you want a .csv as output again 
                            {
                                sb.Append(';');       
                            }     
                        }
                sb.AppendLine(); //add another line to your stringbuilder in which you will store the next column of your datatable
                }
    
    File.WriteAllText("C:\\Users\\moki\\Downloads\\Output.csv", sb.ToString());  //finally create the output .csv  
    

    您当然可以将这两个步骤结合起来。

    【讨论】:

    • 具有mydata.Rows[i][j] i 的行不在上下文中,也在第二个循环datatable.Rows[i][u]
    • 这一行仍然有错误,因为它不在上下文mydata.Rows[i][j] = arr[j];
    • @MokiNex 对不起,另一个复制错误...当然您必须在数据表中添加列和行,再次更新答案。
    • ...此行最初是错误的:for (int j = 0; j &lt; arr.Length; j++) 它以 j=1 开头,但在一些更改前已修复
    • @MokiNex 在代码中添加了 cmets - 希望清楚
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-04
    • 1970-01-01
    • 2021-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多