Programing

C #을 사용하여 CSV 파일 읽기

crosscheck 2020. 6. 7. 10:28
반응형

C #을 사용하여 CSV 파일 읽기


간단한 가져 오기 응용 프로그램을 작성 중이며 CSV 파일을 읽고 결과를 DataGrid표시하고 손상된 다른 CSV 파일 행을 다른 표에 표시해야합니다. 예를 들어 다른 그리드에서 5보다 짧은 선을 표시하십시오. 나는 이것을 이렇게하려고 노력하고있다 :

StreamReader sr = new StreamReader(FilePath);
importingData = new Account();
string line;
string[] row = new string [5];
while ((line = sr.ReadLine()) != null)
{
    row = line.Split(',');

    importingData.Add(new Transaction
    {
        Date = DateTime.Parse(row[0]),
        Reference = row[1],
        Description = row[2],
        Amount = decimal.Parse(row[3]),
        Category = (Category)Enum.Parse(typeof(Category), row[4])
    });
}

그러나이 경우에는 어레이에서 작동하기가 매우 어렵습니다. 값을 나누는 더 좋은 방법이 있습니까?


바퀴를 재발 명하지 마십시오. .NET BCL에 이미있는 기능을 활용하십시오.

  • 에 대한 참조를 추가하십시오 Microsoft.VisualBasic(예, VisualBasic이라고하지만 C #에서도 작동합니다. 결국 모두 IL 일뿐입니다)
  • Microsoft.VisualBasic.FileIO.TextFieldParser클래스를 사용하여 CSV 파일을 구문 분석하십시오.

샘플 코드는 다음과 같습니다.

using (TextFieldParser parser = new TextFieldParser(@"c:\temp\test.csv"))
{
    parser.TextFieldType = FieldType.Delimited;
    parser.SetDelimiters(",");
    while (!parser.EndOfData) 
    {
        //Processing row
        string[] fields = parser.ReadFields();
        foreach (string field in fields) 
        {
            //TODO: Process field
        }
    }
}

C # 프로젝트에서 나에게 효과적입니다.

더 많은 링크 / 정보는 다음과 같습니다.


내 경험은 많은 다른 CSV 형식이 있다는 것입니다. 특히 필드 내에서 따옴표 및 구분 기호 이스케이프 처리 방법.

이것들은 내가 만난 변종입니다.

  • 따옴표는 따옴표로 묶어지고 두 배가됩니다 (예 : 15 "-> field1,"15 "" ", field3
  • 다른 이유로 필드를 인용하지 않으면 따옴표는 변경되지 않습니다. 즉 15 "-> field1,15", fields3
  • 따옴표는 \로 이스케이프됩니다. 즉 15 "-> field1,"15 \ "", field3
  • 따옴표는 전혀 변경되지 않습니다 (항상 올바르게 구문 분석 할 수있는 것은 아닙니다)
  • 구분자는 따옴표로 묶습니다 (excel). 즉 a, b-> field1, "a, b", field3
  • 구분 기호는 \로 이스케이프됩니다. 즉 a, b-> field1, a \, b, field3

기존 csv 파서 중 많은 것을 시도했지만 내가 실행 한 변형을 처리 할 수있는 단일 파서는 없습니다. 파서가 지원하는 이스케이프 변형을 문서에서 찾아내는 것도 어렵습니다.

내 프로젝트에서 VB TextFieldParser 또는 사용자 지정 스플리터를 사용합니다.


Nuget의 CsvHelper를 권장 합니다.

(Microsoft.VisualBasic에 대한 참조를 추가하는 것만으로는 기분이 좋지 않습니다. 추악 할뿐만 아니라 아마도 플랫폼 간이 아닙니다.)


때로는 바퀴를 재발 명하고 싶지 않을 때 라이브러리를 사용하는 것이 좋지만,이 경우 라이브러리를 사용하는 것보다 적은 수의 코드 줄로 동일한 작업을 수행 할 수 있습니다. 사용하기 매우 쉬운 다른 방법이 있습니다.

  1. 이 예제에서는 StreamReader를 사용하여 파일을 읽습니다.
  2. 각 줄에서 구분자를 감지하는 정규식.
  3. 인덱스 0에서 n까지 열을 수집하는 배열

using (StreamReader reader = new StreamReader(fileName))
    {
        string line; 

        while ((line = reader.ReadLine()) != null)
        {
            //Define pattern
            Regex CSVParser = new Regex(",(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))");

            //Separating columns to array
            string[] X = CSVParser.Split(line);

            /* Do something with X */
        }
    }

CSV는 복잡 얻을 수있는 진짜 빨리.

강력하고 잘 테스트 된 것을 사용하십시오.
FileHelpers : www.filehelpers.net

FileHelper는 파일, 문자열 또는 스트림의 고정 길이 또는 구분 된 레코드에서 데이터를 가져 오거나 내보내는 무료 .NET 라이브러리입니다.


나는 이것을 여기에서 사용한다 :

http://www.codeproject.com/KB/database/GenericParser.aspx

지난번에 이런 것을 찾고 있었을 때이 질문에 대한 답으로 찾았습니다 .


이 목록의 또 다른 하나 인 Cinchoo ETL -CSV 파일을 읽고 쓰는 오픈 소스 라이브러리

아래 샘플 CSV 파일

Id, Name
1, Tom
2, Mark

아래와 같이 라이브러리를 사용하여 빠르게로드 할 수 있습니다

using (var reader = new ChoCSVReader("test.csv").WithFirstLineHeader())
{
   foreach (dynamic item in reader)
   {
      Console.WriteLine(item.Id);
      Console.WriteLine(item.Name);
   }
}

CSV 파일과 일치하는 POCO 클래스가있는 경우

public class Employee
{
   public int Id { get; set; }
   public string Name { get; set; }
}

아래와 같이 CSV 파일을로드 할 수 있습니다

using (var reader = new ChoCSVReader<Employee>("test.csv").WithFirstLineHeader())
{
   foreach (var item in reader)
   {
      Console.WriteLine(item.Id);
      Console.WriteLine(item.Name);
   }
}

CodeProject 에서 사용 방법에 대한 기사를 확인 하십시오.

면책 조항 : 나는이 도서관의 저자입니다


private static DataTable ConvertCSVtoDataTable(string strFilePath)
        {
            DataTable dt = new DataTable();
            using (StreamReader sr = new StreamReader(strFilePath))
            {
                string[] headers = sr.ReadLine().Split(',');
                foreach (string header in headers)
                {
                    dt.Columns.Add(header);
                }
                while (!sr.EndOfStream)
                {
                    string[] rows = sr.ReadLine().Split(',');
                    DataRow dr = dt.NewRow();
                    for (int i = 0; i < headers.Length; i++)
                    {
                        dr[i] = rows[i];
                    }
                    dt.Rows.Add(dr);
                }

            }

            return dt;
        }

        private static void WriteToDb(DataTable dt)
        {
            string connectionString =
                "Data Source=localhost;" +
                "Initial Catalog=Northwind;" +
                "Integrated Security=SSPI;";

            using (SqlConnection con = new SqlConnection(connectionString))
                {
                    using (SqlCommand cmd = new SqlCommand("spInsertTest", con))
                    {
                        cmd.CommandType = CommandType.StoredProcedure;

                        cmd.Parameters.Add("@policyID", SqlDbType.Int).Value = 12;
                        cmd.Parameters.Add("@statecode", SqlDbType.VarChar).Value = "blagh2";
                        cmd.Parameters.Add("@county", SqlDbType.VarChar).Value = "blagh3";

                        con.Open();
                        cmd.ExecuteNonQuery();
                    }
                }

         }

우선 CSV 란 무엇이며 어떻게 작성해야하는지 이해해야합니다.

  1. 모든 다음 문자열 ( /r/n)은 다음 "테이블"행입니다.
  2. "표"셀은 일부 구분 기호로 구분됩니다. 가장 많이 사용되는 기호는 \t또는,
  3. 모든 셀은이 구분 기호를 포함 할 수 있습니다 (셀은 따옴표로 시작하고이 경우이 기호로 끝나야합니다)
  4. 모든 셀은 /r/n시볼 을 포함 할 수 있습니다 (셀은 따옴표로 시작하고이 경우이 기호로 끝나야합니다)

C # / Visual Basic이 CSV 파일을 사용하는 가장 쉬운 방법은 표준 Microsoft.VisualBasic라이브러리 를 사용하는 것 입니다. 필요한 참조와 클래스에 다음 문자열을 추가하기 만하면됩니다.

using Microsoft.VisualBasic.FileIO;

Yes, you can use it in C#, don't worry. This library can read relatively big files and supports all of needed rules, so you will be able to work with all of CSV files.

Some time ago I had wrote simple class for CSV read/write based on this library. Using this simple class you will be able to work with CSV like with 2 dimensions array. You can find my class by the following link: https://github.com/ukushu/DataExporter

Simple example of using:

Csv csv = new Csv("\t");//delimiter symbol

csv.FileOpen("c:\\file1.csv");

var row1Cell6Value = csv.Rows[0][5];

csv.AddRow("asdf","asdffffff","5")

csv.FileSave("c:\\file2.csv");

To complete the previous answers, one may need a collection of objects from his CSV File, either parsed by the TextFieldParser or the string.Split method, and then each line converted to an object via Reflection. You obviously first need to define a class that matches the lines of the CSV file.

I used the simple CSV Serializer from Michael Kropat found here: Generic class to CSV (all properties) and reused his methods to get the fields and properties of the wished class.

I deserialize my CSV file with the following method:

public static IEnumerable<T> ReadCsvFileTextFieldParser<T>(string fileFullPath, string delimiter = ";") where T : new()
{
    if (!File.Exists(fileFullPath))
    {
        return null;
    }

    var list = new List<T>();
    var csvFields = GetAllFieldOfClass<T>();
    var fieldDict = new Dictionary<int, MemberInfo>();

    using (TextFieldParser parser = new TextFieldParser(fileFullPath))
    {
        parser.SetDelimiters(delimiter);

        bool headerParsed = false;

        while (!parser.EndOfData)
        {
            //Processing row
            string[] rowFields = parser.ReadFields();
            if (!headerParsed)
            {
                for (int i = 0; i < rowFields.Length; i++)
                {
                    // First row shall be the header!
                    var csvField = csvFields.Where(f => f.Name == rowFields[i]).FirstOrDefault();
                    if (csvField != null)
                    {
                        fieldDict.Add(i, csvField);
                    }
                }
                headerParsed = true;
            }
            else
            {
                T newObj = new T();
                for (int i = 0; i < rowFields.Length; i++)
                {
                    var csvFied = fieldDict[i];
                    var record = rowFields[i];

                    if (csvFied is FieldInfo)
                    {
                        ((FieldInfo)csvFied).SetValue(newObj, record);
                    }
                    else if (csvFied is PropertyInfo)
                    {
                        var pi = (PropertyInfo)csvFied;
                        pi.SetValue(newObj, Convert.ChangeType(record, pi.PropertyType), null);
                    }
                    else
                    {
                        throw new Exception("Unhandled case.");
                    }
                }
                if (newObj != null)
                {
                    list.Add(newObj);
                }
            }
        }
    }
    return list;
}

public static IEnumerable<MemberInfo> GetAllFieldOfClass<T>()
{
    return
        from mi in typeof(T).GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)
        where new[] { MemberTypes.Field, MemberTypes.Property }.Contains(mi.MemberType)
        let orderAttr = (ColumnOrderAttribute)Attribute.GetCustomAttribute(mi, typeof(ColumnOrderAttribute))
        orderby orderAttr == null ? int.MaxValue : orderAttr.Order, mi.Name
        select mi;            
}

참고URL : https://stackoverflow.com/questions/3507498/reading-csv-files-using-c-sharp

반응형