Phân tích tệp CSV trong C #, với tiêu đề


266

Có cách mặc định / chính thức / được đề xuất để phân tích các tệp CSV trong C # không? Tôi không muốn cuộn trình phân tích cú pháp của riêng tôi.

Ngoài ra, tôi đã thấy các trường hợp người sử dụng ODBC / OLE DB để đọc CSV thông qua trình điều khiển Văn bản và rất nhiều người không khuyến khích điều này do "nhược điểm" của nó. Những nhược điểm này là gì?

Lý tưởng nhất là tôi đang tìm cách để tôi có thể đọc CSV theo tên cột, sử dụng bản ghi đầu tiên làm tên tiêu đề / trường. Một số câu trả lời được đưa ra là chính xác nhưng về cơ bản là giải tuần tự hóa tệp thành các lớp.

Câu trả lời:


138

Hãy để một thư viện xử lý tất cả các chi tiết khó chịu cho bạn! :-)

Kiểm tra FileHelpers và ở lại DRY - Đừng lặp lại chính mình - không cần phải phát minh lại bánh xe một lần đáng kinh ngạc ....

Về cơ bản, bạn chỉ cần xác định hình dạng dữ liệu đó - các trường trong dòng riêng lẻ của bạn trong CSV - bằng một lớp công khai (và các thuộc tính được suy nghĩ kỹ như giá trị mặc định, thay thế cho giá trị NULL, v.v.) công cụ FileHelpers tại một tệp và bingo - bạn lấy lại tất cả các mục từ tệp đó. Một thao tác đơn giản - hiệu suất tuyệt vời!


1
cho đến khi bạn cần sth thực sự tùy chỉnh (và hầu hết có thể được triển khai dưới dạng tiện ích mở rộng) FileHelpers là cách tốt nhất để đi, giải pháp thực sự thuận tiện, đã được thử nghiệm và hoạt động tốt
mikus

3
Kể từ ngày 1 tháng 6 năm 2015, cách duy nhất tôi có thể tải xuống FileHelpers là tìm kiếm nó trên sourceforge.net. Đây là liên kết được sử dụng: sourceforge.net/projects/filehelpers/?source=directory
Sudhanshu Mishra

2
@dotnetguy chúng tôi đang trong quá trình phát hành 3.1 (hiện tại là 3.1-RC2). Ngoài ra, chúng tôi đã thiết kế lại trang web: www.filehelpers.net bạn có thể tải xuống phiên bản mới nhất từ ​​đó
Marcos Meli

1
@MarcosMeli cảm ơn nhiều! Tôi đã sử dụng FileHelpers trong một trong các dự án của mình và thật dễ dàng để sử dụng - danh tiếng cho nhóm. Tôi đang lên kế hoạch cho một blog trên đó sớm và btw - Yêu trang web mới - hoàn thành tốt!
Sudhanshu Mishra

FileHelpers không xử lý dấu phẩy được trích dẫn trong CSV một cách chính xác hoặc thực tế là ánh xạ các tiêu đề trường, thay vào đó, các cột sẽ theo thứ tự như các trường được khai báo theo kiểu của bạn. Cá nhân tôi sẽ không sử dụng nó.
Alastair Maw

358

Trình phân tích cú pháp CSV hiện là một phần của .NET Framework.

Thêm một tham chiếu đến Microsoft.VisualBasic.dll (hoạt động tốt trong C #, đừng bận tâm đến tên)

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

Các tài liệu ở đây - Lớp TextFieldParser

PS Nếu bạn cần một nhà xuất khẩu CSV , hãy thử CsvExport (tiết lộ: Tôi là một trong những người đóng góp)


2
Theo kinh nghiệm của tôi, TextFieldParser không hoạt động tốt với các tệp lớn (ví dụ> 250Mb). :(
MBoros

6
TextFieldParser triển khai IDis Dùng một lần, vì vậy có thể tốt nhất để sử dụng nó trong một mệnh đề sử dụng. Tốt trả lời khác.
Chris Bush

3
Trong hàm tạo, bạn có thể muốn sử dụng một mã hóa khác với mã hóa theo mặc định, như vậy: TextFieldParser mới ("c: \ temp \ test.csv", System.Text.Encoding.UTF8)
neural5torm

1
Lưu ý rằng nếu bất kỳ trường nào trong CSV của bạn chứa các dòng trống, chúng sẽ bị bỏ qua TextFieldParser.ReadLine(). Xem tài liệu TextFieldParser
mcNux

3
Có cách nào để có được điều này trong .NET Core không?
Hugo Zink

183

CsvHelper (thư viện tôi duy trì) sẽ đọc tệp CSV vào các đối tượng tùy chỉnh.

var csv = new CsvReader( File.OpenText( "file.csv" ) );
var myCustomObjects = csv.GetRecords<MyCustomObject>();

Đôi khi bạn không sở hữu các đối tượng bạn đang cố đọc. Trong trường hợp này, bạn có thể sử dụng ánh xạ lưu loát vì bạn không thể đặt các thuộc tính trên lớp.

public sealed class MyCustomObjectMap : CsvClassMap<MyCustomObject>
{
    public MyCustomObjectMap()
    {
        Map( m => m.Property1 ).Name( "Column Name" );
        Map( m => m.Property2 ).Index( 4 );
        Map( m => m.Property3 ).Ignore();
        Map( m => m.Property4 ).TypeConverter<MySpecialTypeConverter>();
    }
}

BIÊN TẬP:

CsvReader hiện yêu cầu CultureInfo được truyền vào bộ tạo ( https://github.com/JoshClose/CsvHelper/issues/1441 ).

Thí dụ:

var csv = new CsvReader(File.OpenText("file.csv"), System.Globalization.CultureInfo.CurrentCulture);

18
Tôi đồng ý với @ kubal5003. Điều bán cho tôi là bạn có sẵn gói NuGet. Cảm ơn người đàn ông, nó rất nhanh, và tất cả các csv tôi đọc.
Gromer

7
Thật nhanh quá. 1,3 triệu hồ sơ được đọc và giải trừ trong 10 giây.
marisks

2
Thư viện lớn rất dễ thực hiện. Tôi chỉ đề nghị Josh cập nhật câu trả lời của anh ấy ở đây vì thư viện đã thay đổi một chút vì câu trả lời này đã được viết và bạn không thể khởi tạo CsvHelper nữa (bây giờ chỉ là một không gian tên) nhưng bạn phải sử dụng lớp CsvReader.
Marko

1
CsvClassMap dường như không tồn tại trong phiên bản cuối cùng của CsvHelper?
knocte

1
knocte, bây giờ nó được gọi là ClassMap. Cũng có những thay đổi khác, như phải đọc trước khi yêu cầu bản ghi tiêu đề (bằng cách này được đặt thành bất cứ điều gì đã được đọc bởi cuộc gọi đầu tiên đến Read ()). Giống như những người khác đã đề cập trước đây, nó rất nhanh và dễ làm việc.
norgie

31

Trong một ứng dụng kinh doanh, tôi sử dụng dự án Nguồn mở trên codeproject.com, CSVReader .

Nó hoạt động tốt, và có hiệu suất tốt. Có một số điểm chuẩn trên liên kết tôi cung cấp.

Một ví dụ đơn giản, được sao chép từ trang dự án:

using (CsvReader csv = new CsvReader(new StreamReader("data.csv"), true))
{
    int fieldCount = csv.FieldCount;
    string[] headers = csv.GetFieldHeaders();

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

        Console.WriteLine();
    }
}

Như bạn có thể thấy, nó rất dễ làm việc.



12

Nếu bạn chỉ cần đọc file csv sau đó tôi khuyên bạn nên thư viện này: Một nhanh CSV đọc
Nếu bạn cũng cần phải tạo ra file csv sau đó sử dụng cái này: FileHelpers

Cả hai đều miễn phí và mã nguồn mở.


FileHelpers có một bản tóm tắt hấp dẫn: filehelpers.com FileHelpers là một thư viện .NET miễn phí và dễ sử dụng để nhập / xuất dữ liệu từ các bản ghi có độ dài cố định hoặc phân tách trong tệp, chuỗi hoặc luồng.
AnneTheAgile

Mặc dù liên kết này có thể trả lời câu hỏi, nhưng các câu trả lời chỉ liên kết không được khuyến khích trên Stack Overflow, bạn có thể cải thiện câu trả lời này bằng cách lấy các phần quan trọng của liên kết và đưa nó vào câu trả lời của bạn, điều này đảm bảo câu trả lời của bạn vẫn là câu trả lời nếu liên kết bị thay đổi hoặc bị xóa :)
WhatsThePoint

11

Đây là một lớp trợ giúp tôi sử dụng thường xuyên, trong trường hợp bất kỳ ai trở lại chủ đề này (tôi muốn chia sẻ nó).

Tôi sử dụng điều này vì sự đơn giản của việc chuyển nó vào các dự án đã sẵn sàng để sử dụng:

public class CSVHelper : List<string[]>
{
  protected string csv = string.Empty;
  protected string separator = ",";

  public CSVHelper(string csv, string separator = "\",\"")
  {
    this.csv = csv;
    this.separator = separator;

    foreach (string line in Regex.Split(csv, System.Environment.NewLine).ToList().Where(s => !string.IsNullOrEmpty(s)))
    {
      string[] values = Regex.Split(line, separator);

      for (int i = 0; i < values.Length; i++)
      {
        //Trim values
        values[i] = values[i].Trim('\"');
      }

      this.Add(values);
    }
  }
}

Và sử dụng nó như:

public List<Person> GetPeople(string csvContent)
{
  List<Person> people = new List<Person>();
  CSVHelper csv = new CSVHelper(csvContent);
  foreach(string[] line in csv)
  {
    Person person = new Person();
    person.Name = line[0];
    person.TelephoneNo = line[1];
    people.Add(person);
  }
  return people;
}

[Trình trợ giúp csv được cập nhật: đã sửa lỗi trong đó ký tự dòng mới cuối cùng tạo dòng mới]


17
nếu bất kỳ mục csv nào chứa dấu phẩy (,) thì mã này sẽ không hoạt động.
hakan

Để giữ cho mọi thứ nhẹ nhàng, tôi đã sử dụng một nhân vật ống làm người tách biệt. '|'
Base33

giải pháp tuyệt vời. Chỉ là một câu hỏi về đoạn 2. Loại đối tượng là Người
Ca cao Dev

@CocoaDev Đây là một lớp có chứa hai thuộc tính chuỗi - Tên và Điện thoại. Hoàn toàn cho ví dụ mặc dù. Nếu bất kỳ thuộc tính nào là số nguyên thì đó chỉ là một chuyển đổi thẳng (có kiểm tra?).
Base33

10

Giải pháp này đang sử dụng hội đồng Microsoft.VisualBasic chính thức để phân tích CSV.

Ưu điểm:

  • dấu phân cách thoát
  • bỏ qua tiêu đề
  • cắt không gian
  • bỏ qua ý kiến

Mã số:

    using Microsoft.VisualBasic.FileIO;

    public static List<List<string>> ParseCSV (string csv)
    {
        List<List<string>> result = new List<List<string>>();


        // To use the TextFieldParser a reference to the Microsoft.VisualBasic assembly has to be added to the project. 
        using (TextFieldParser parser = new TextFieldParser(new StringReader(csv))) 
        {
            parser.CommentTokens = new string[] { "#" };
            parser.SetDelimiters(new string[] { ";" });
            parser.HasFieldsEnclosedInQuotes = true;

            // Skip over header line.
            //parser.ReadLine();

            while (!parser.EndOfData)
            {
                var values = new List<string>();

                var readFields = parser.ReadFields();
                if (readFields != null)
                    values.AddRange(readFields);
                result.Add(values);
            }
        }

        return result;
    }

7

Tôi đã viết TinyCsvParser cho .NET, đây là một trong những trình phân tích cú pháp .NET nhanh nhất và có khả năng cấu hình cao để phân tích hầu hết mọi định dạng CSV.

Nó được phát hành theo Giấy phép MIT:

Bạn có thể sử dụng NuGet để cài đặt nó. Chạy lệnh sau trong Bảng điều khiển quản lý gói .

PM> Install-Package TinyCsvParser

Sử dụng

Hãy tưởng tượng chúng ta có danh sách Người trong tệp CSV persons.csvcó tên, họ và ngày sinh của họ.

FirstName;LastName;BirthDate
Philipp;Wagner;1986/05/12
Max;Musterman;2014/01/02

Mô hình miền tương ứng trong hệ thống của chúng tôi có thể trông như thế này.

private class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime BirthDate { get; set; }
}

Khi sử dụng TinyCsvParser, bạn phải xác định ánh xạ giữa các cột trong dữ liệu CSV và thuộc tính trong mô hình miền của bạn.

private class CsvPersonMapping : CsvMapping<Person>
{

    public CsvPersonMapping()
        : base()
    {
        MapProperty(0, x => x.FirstName);
        MapProperty(1, x => x.LastName);
        MapProperty(2, x => x.BirthDate);
    }
}

Và sau đó chúng ta có thể sử dụng ánh xạ để phân tích dữ liệu CSV bằng a CsvParser.

namespace TinyCsvParser.Test
{
    [TestFixture]
    public class TinyCsvParserTest
    {
        [Test]
        public void TinyCsvTest()
        {
            CsvParserOptions csvParserOptions = new CsvParserOptions(true, new[] { ';' });
            CsvPersonMapping csvMapper = new CsvPersonMapping();
            CsvParser<Person> csvParser = new CsvParser<Person>(csvParserOptions, csvMapper);

            var result = csvParser
                .ReadFromFile(@"persons.csv", Encoding.ASCII)
                .ToList();

            Assert.AreEqual(2, result.Count);

            Assert.IsTrue(result.All(x => x.IsValid));

            Assert.AreEqual("Philipp", result[0].Result.FirstName);
            Assert.AreEqual("Wagner", result[0].Result.LastName);

            Assert.AreEqual(1986, result[0].Result.BirthDate.Year);
            Assert.AreEqual(5, result[0].Result.BirthDate.Month);
            Assert.AreEqual(12, result[0].Result.BirthDate.Day);

            Assert.AreEqual("Max", result[1].Result.FirstName);
            Assert.AreEqual("Mustermann", result[1].Result.LastName);

            Assert.AreEqual(2014, result[1].Result.BirthDate.Year);
            Assert.AreEqual(1, result[1].Result.BirthDate.Month);
            Assert.AreEqual(1, result[1].Result.BirthDate.Day);
        }
    }
}

Hướng dẫn sử dụng

Hướng dẫn sử dụng đầy đủ có sẵn tại:


1

Đây là triển khai KISS của tôi ...

using System;
using System.Collections.Generic;
using System.Text;

class CsvParser
{
    public static List<string> Parse(string line)
    {
        const char escapeChar = '"';
        const char splitChar = ',';
        bool inEscape = false;
        bool priorEscape = false;

        List<string> result = new List<string>();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < line.Length; i++)
        {
            char c = line[i];
            switch (c)
            {
                case escapeChar:
                    if (!inEscape)
                        inEscape = true;
                    else
                    {
                        if (!priorEscape)
                        {
                            if (i + 1 < line.Length && line[i + 1] == escapeChar)
                                priorEscape = true;
                            else
                                inEscape = false;
                        }
                        else
                        {
                            sb.Append(c);
                            priorEscape = false;
                        }
                    }
                    break;
                case splitChar:
                    if (inEscape) //if in escape
                        sb.Append(c);
                    else
                    {
                        result.Add(sb.ToString());
                        sb.Length = 0;
                    }
                    break;
                default:
                    sb.Append(c);
                    break;
            }
        }

        if (sb.Length > 0)
            result.Add(sb.ToString());

        return result;
    }

}

1
Điều này không giải quyết các ngắt dòng trong các chuỗi được trích dẫn hợp lệ trong tệp CSV.
John Leidegren

Alex, điều John đang cố nói là RFC 4180 ( ietf.org/rfc/rfc4180.txt - Xem phần 2 và mục 6) cho phép một cột có CR LF ở giữa cột có hiệu quả lan truyền nó 2 dòng trong một tập tin. Giải pháp của bạn có thể sẽ hoạt động tốt trong hầu hết các trường hợp (đặc biệt là nếu các tệp CSV được tạo bằng cách lưu ra khỏi Excel), nhưng nó không bao gồm trường hợp cạnh này. CsvHelper, được đề cập ở trên, được cho là sẽ xem xét trường hợp này.
David Yates

Đúng, điều này là đúng, nhưng nếu bạn có CR LF trong CSV của mình, có thể bạn không nên sử dụng CSV, nhưng một cái gì đó phù hợp hơn như, json hoặc xml hoặc định dạng độ dài cố định.
Alex Bắt đầu

1

Cách đây một thời gian, tôi đã viết một lớp đơn giản để đọc / ghi CSV dựa trên Microsoft.VisualBasicthư viện. Sử dụng lớp đơn giản này, bạn sẽ có thể làm việc với CSV như với mảng 2 chiều. Bạn có thể tìm thấy lớp học của tôi bằng liên kết sau: https://github.com/ukushu/DataExporter

Ví dụ đơn giản về cách sử dụng:

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");

Để đọc tiêu đề, bạn chỉ cần đọc csv.Rows[0]các ô :)


1

Giải pháp tập tin nguồn đơn cho nhu cầu phân tích cú pháp đơn giản, hữu ích. Thỏa thuận với tất cả các trường hợp cạnh khó chịu. Chẳng hạn như chuẩn hóa dòng mới và xử lý các dòng mới trong chuỗi ký tự được trích dẫn. Chào mừng bạn!

Nếu tệp CSV của bạn có một tiêu đề, bạn chỉ cần đọc tên cột (và tính toán các chỉ mục cột) từ hàng đầu tiên. Đơn giản như vậy.

Lưu ý rằng đó Dumplà phương pháp LINQPad, bạn có thể muốn xóa phương thức đó nếu bạn không sử dụng LINQPad.

void Main()
{
    var file1 = "a,b,c\r\nx,y,z";
    CSV.ParseText(file1).Dump();

    var file2 = "a,\"b\",c\r\nx,\"y,z\"";
    CSV.ParseText(file2).Dump();

    var file3 = "a,\"b\",c\r\nx,\"y\r\nz\"";
    CSV.ParseText(file3).Dump();

    var file4 = "\"\"\"\"";
    CSV.ParseText(file4).Dump();
}

static class CSV
{
    public struct Record
    {
        public readonly string[] Row;

        public string this[int index] => Row[index];

        public Record(string[] row)
        {
            Row = row;
        }
    }

    public static List<Record> ParseText(string text)
    {
        return Parse(new StringReader(text));
    }

    public static List<Record> ParseFile(string fn)
    {
        using (var reader = File.OpenText(fn))
        {
            return Parse(reader);
        }
    }

    public static List<Record> Parse(TextReader reader)
    {
        var data = new List<Record>();

        var col = new StringBuilder();
        var row = new List<string>();
        for (; ; )
        {
            var ln = reader.ReadLine();
            if (ln == null) break;
            if (Tokenize(ln, col, row))
            {
                data.Add(new Record(row.ToArray()));
                row.Clear();
            }
        }

        return data;
    }

    public static bool Tokenize(string s, StringBuilder col, List<string> row)
    {
        int i = 0;

        if (col.Length > 0)
        {
            col.AppendLine(); // continuation

            if (!TokenizeQuote(s, ref i, col, row))
            {
                return false;
            }
        }

        while (i < s.Length)
        {
            var ch = s[i];
            if (ch == ',')
            {
                row.Add(col.ToString().Trim());
                col.Length = 0;
                i++;
            }
            else if (ch == '"')
            {
                i++;
                if (!TokenizeQuote(s, ref i, col, row))
                {
                    return false;
                }
            }
            else
            {
                col.Append(ch);
                i++;
            }
        }

        if (col.Length > 0)
        {
            row.Add(col.ToString().Trim());
            col.Length = 0;
        }

        return true;
    }

    public static bool TokenizeQuote(string s, ref int i, StringBuilder col, List<string> row)
    {
        while (i < s.Length)
        {
            var ch = s[i];
            if (ch == '"')
            {
                // escape sequence
                if (i + 1 < s.Length && s[i + 1] == '"')
                {
                    col.Append('"');
                    i++;
                    i++;
                    continue;
                }
                i++;
                return true;
            }
            else
            {
                col.Append(ch);
                i++;
            }
        }
        return false;
    }
}

1

Một cái khác trong danh sách này, Cinchoo ETL - một thư viện mã nguồn mở để đọc và viết nhiều định dạng tệp (CSV, tệp phẳng, Xml, JSON, v.v.)

Mẫu bên dưới cho thấy cách đọc tệp CSV nhanh chóng (Không yêu cầu đối tượng POCO)

string csv = @"Id, Name
1, Carl
2, Tom
3, Mark";

using (var p = ChoCSVReader.LoadText(csv)
    .WithFirstLineHeader()
    )
{
    foreach (var rec in p)
    {
        Console.WriteLine($"Id: {rec.Id}");
        Console.WriteLine($"Name: {rec.Name}");
    }
}

Mẫu bên dưới cho thấy cách đọc tệp CSV bằng đối tượng POCO

public partial class EmployeeRec
{
    public int Id { get; set; }
    public string Name { get; set; }
}

static void CSVTest()
{
    string csv = @"Id, Name
1, Carl
2, Tom
3, Mark";

    using (var p = ChoCSVReader<EmployeeRec>.LoadText(csv)
        .WithFirstLineHeader()
        )
    {
        foreach (var rec in p)
        {
            Console.WriteLine($"Id: {rec.Id}");
            Console.WriteLine($"Name: {rec.Name}");
        }
    }
}

Vui lòng kiểm tra các bài viết tại CodeProject về cách sử dụng nó.


0

Dựa trên bài đăng của unimit về Cách phân chia CSV đúng cách bằng hàm C # split ()? :

string[] tokens = System.Text.RegularExpressions.Regex.Split(paramString, ",");

LƯU Ý: điều này không xử lý dấu phẩy thoát / lồng nhau, v.v., và do đó chỉ phù hợp với một số danh sách CSV đơn giản nhất định.


2
Điều này rất tệ và có khả năng chậm :)
EKS

1
Có thể, nhưng nó hoạt động hoàn hảo và đơn giản cho một tập hợp nhỏ các tham số, do đó là một giải pháp hợp lệ và hữu ích. Tại sao downvote nó? "Rất tệ" là một chút cực đoan, bạn có nghĩ vậy không?
radsdau

1
Nó không xử lý dấu phẩy thoát / lồng nhau, v.v. Sẽ hoạt động trong một số trường hợp nhưng chắc chắn sẽ không hoạt động đối với tất cả các tệp csv
NStuke

Bạn đúng rồi; Tôi sẽ chỉnh sửa trả lời để phản ánh điều đó. Cảm ơn. Nhưng nó vẫn có chỗ đứng của nó.
radsdau

Điều này hoạt động hoàn hảo cho trường hợp sử dụng của tôi khi tôi đang xây dựng một máy chủ sql clr dll và không thể sử dụng bất kỳ gói bên ngoài nào khác. Tôi chỉ cần phân tích một tệp csv đơn giản với tên tệp và số hàng.
dubvfan87

0

Mã này đọc csv vào DataTable:

public static DataTable ReadCsv(string path)
{
    DataTable result = new DataTable("SomeData");
    using (TextFieldParser parser = new TextFieldParser(path))
    {
        parser.TextFieldType = FieldType.Delimited;
        parser.SetDelimiters(",");
        bool isFirstRow = true;
        //IList<string> headers = new List<string>();

        while (!parser.EndOfData)
        {
            string[] fields = parser.ReadFields();
            if (isFirstRow)
            {
                foreach (string field in fields)
                {
                    result.Columns.Add(new DataColumn(field, typeof(string)));
                }
                isFirstRow = false;
            }
            else
            {
                int i = 0;
                DataRow row = result.NewRow();
                foreach (string field in fields)
                {
                    row[i++] = field;
                }
                result.Rows.Add(row);
            }
        }
    }
    return result;
}

1
TextFieldParser có trong Microsoft.VisualBasic.dll.
dùng3285954

0

Nếu bất cứ ai muốn một đoạn mã, họ có thể nhập mã của họ mà không cần phải liên kết thư viện hoặc tải xuống gói. Đây là một phiên bản tôi đã viết:

    public static string FormatCSV(List<string> parts)
    {
        string result = "";

        foreach (string s in parts)
        {
            if (result.Length > 0)
            {
                result += ",";

                if (s.Length == 0)
                    continue;
            }

            if (s.Length > 0)
            {
                result += "\"" + s.Replace("\"", "\"\"") + "\"";
            }
            else
            {
                // cannot output double quotes since its considered an escape for a quote
                result += ",";
            }
        }

        return result;
    }

    enum CSVMode
    {
        CLOSED = 0,
        OPENED_RAW = 1,
        OPENED_QUOTE = 2
    }

    public static List<string> ParseCSV(string input)
    {
        List<string> results;

        CSVMode mode;

        char[] letters;

        string content;


        mode = CSVMode.CLOSED;

        content = "";
        results = new List<string>();
        letters = input.ToCharArray();

        for (int i = 0; i < letters.Length; i++)
        {
            char letter = letters[i];
            char nextLetter = '\0';

            if (i < letters.Length - 1)
                nextLetter = letters[i + 1];

            // If its a quote character
            if (letter == '"')
            {
                // If that next letter is a quote
                if (nextLetter == '"' && mode == CSVMode.OPENED_QUOTE)
                {
                    // Then this quote is escaped and should be added to the content

                    content += letter;

                    // Skip the escape character
                    i++;
                    continue;
                }
                else
                {
                    // otherwise its not an escaped quote and is an opening or closing one
                    // Character is skipped

                    // If it was open, then close it
                    if (mode == CSVMode.OPENED_QUOTE)
                    {
                        results.Add(content);

                        // reset the content
                        content = "";

                        mode = CSVMode.CLOSED;

                        // If there is a next letter available
                        if (nextLetter != '\0')
                        {
                            // If it is a comma
                            if (nextLetter == ',')
                            {
                                i++;
                                continue;
                            }
                            else
                            {
                                throw new Exception("Expected comma. Found: " + nextLetter);
                            }
                        }
                    }
                    else if (mode == CSVMode.OPENED_RAW)
                    {
                        // If it was opened raw, then just add the quote 
                        content += letter;
                    }
                    else if (mode == CSVMode.CLOSED)
                    {
                        // Otherwise open it as a quote 

                        mode = CSVMode.OPENED_QUOTE;
                    }
                }
            }
            // If its a comma seperator
            else if (letter == ',')
            {
                // If in quote mode
                if (mode == CSVMode.OPENED_QUOTE)
                {
                    // Just read it
                    content += letter;
                }
                // If raw, then close the content
                else if (mode == CSVMode.OPENED_RAW)
                {
                    results.Add(content);

                    content = "";

                    mode = CSVMode.CLOSED;
                }
                // If it was closed, then open it raw
                else if (mode == CSVMode.CLOSED)
                {
                    mode = CSVMode.OPENED_RAW;

                    results.Add(content);

                    content = "";
                }
            }
            else
            {
                // If opened quote, just read it
                if (mode == CSVMode.OPENED_QUOTE)
                {
                    content += letter;
                }
                // If opened raw, then read it
                else if (mode == CSVMode.OPENED_RAW)
                {
                    content += letter;
                }
                // It closed, then open raw
                else if (mode == CSVMode.CLOSED)
                {
                    mode = CSVMode.OPENED_RAW;

                    content += letter;
                }
            }
        }

        // If it was still reading when the buffer finished
        if (mode != CSVMode.CLOSED)
        {
            results.Add(content);
        }

        return results;
    }

0

Đây là một giải pháp ngắn và đơn giản.

                using (TextFieldParser parser = new TextFieldParser(outputLocation))
                 {
                        parser.TextFieldType = FieldType.Delimited;
                        parser.SetDelimiters(",");
                        string[] headers = parser.ReadLine().Split(',');
                        foreach (string header in headers)
                        {
                            dataTable.Columns.Add(header);
                        }
                        while (!parser.EndOfData)
                        {
                            string[] fields = parser.ReadFields();
                            dataTable.Rows.Add(fields);
                        }
                    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.