CSV文件导入.Net

Mat*_*ttH 104 c# vb.net csv import file

我意识到这是一个新手问题,但我正在寻找一个简单的解决方案 - 似乎应该有一个.

将CSV文件导入强类型数据结构的最佳方法是什么?再简单=更好.

Mar*_*rkJ 74

Microsoft的TextFieldParser稳定,并遵循RFC 4180的CSV文件.不要被Microsoft.VisualBasic名称空间拖延; 它是.NET Framework中的标准组件,只需添加对全局Microsoft.VisualBasic程序集的引用即可.

如果您正在为Windows编译(而不是Mono)并且不期望必须解析"破坏"(不符合RFC的)CSV文件,那么这将是明显的选择,因为它是免费的,不受限制的,稳定的,并积极支持,其中大部分都不能用于FileHelpers.

另请参阅:如何:在Visual Basic中读取逗号分隔的文本文件以获取VB代码示例.

  • 除了不幸命名的命名空间之外,实际上没有关于这个类的特定于VB的内容.如果我只需要一个"简单"的CSV解析器,我肯定会选择这个库,因为一般来说没有什么可以下载,分发或担心的.为此,我编辑了这个答案中以VB为中心的措辞. (2认同)

Not*_*elf 51

查看FileHelpers开源库.

  • @John,你为什么这么说?除非您修改库本身,否则LGPL不要求您发布任何代码.(无论如何,提交补丁是有意义的.) (5认同)
  • @Zeus,我仍然认为你不必发布你的"使用图书馆的作品"的来源.您需要发布"对象代码和/或源代码".我不确定.Net环境中的含义是什么.但你是对的.第6节的要求非常繁重.多么荒谬的许可证. (5认同)
  • @dangph我认为这不是真的.http://www.opensource.org/licenses/lgpl-2.1.php声明"但是,将"使用库的工作"与库链接会创建一个可执行文件,它是库的衍生物...因此可执行文件本许可证涵盖的内容.第6节规定了此类可执行文件的分发条款." (4认同)
  • 相比之下,NHibernate也是LGPL,它已被用于无数的商业应用程序.所以没什么好担心的. (3认同)
  • FileHelpers的另一个问题是,自2007年以来,它的开发似乎已完全停滞.不幸的是,它包含了错误.(对于简单的情况,它可能会正常工作.)即使它是开源的,也不清楚作者是否接受补丁. (2认同)

Kev*_*vin 21

使用OleDB连接.

String sConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\\InputDirectory\\;Extended Properties='text;HDR=Yes;FMT=Delimited'";
OleDbConnection objConn = new OleDbConnection(sConnectionString);
objConn.Open();
DataTable dt = new DataTable();
OleDbCommand objCmdSelect = new OleDbCommand("SELECT * FROM file.csv", objConn);
OleDbDataAdapter objAdapter1 = new OleDbDataAdapter();
objAdapter1.SelectCommand = objCmdSelect;
objAdapter1.Fill(dt);
objConn.Close();
Run Code Online (Sandbox Code Playgroud)

  • @UserControl,当然需要文件系统访问权限.他询问有关导入CSV文件的问题 (3认同)

Jon*_*jap 12

如果您期望CSV解析的相当复杂的场景,甚至不要想到滚动我们自己的解析器.有很多优秀的工具,比如FileHelpers,甚至是CodeProject的工具.

关键是这是一个相当普遍的问题,你可以打赌许多软件开发人员已经考虑并解决了这个问题.


ICR*_*ICR 9

Brian为将其转换为强类型集合提供了一个很好的解决方案.

给出的大多数CSV解析方法都没有考虑转义字段或CSV文件的其他一些细微之处(如修剪字段).这是我个人使用的代码.它的边缘有点粗糙,并且几乎没有错误报告.

public static IList<IList<string>> Parse(string content)
{
    IList<IList<string>> records = new List<IList<string>>();

    StringReader stringReader = new StringReader(content);

    bool inQoutedString = false;
    IList<string> record = new List<string>();
    StringBuilder fieldBuilder = new StringBuilder();
    while (stringReader.Peek() != -1)
    {
        char readChar = (char)stringReader.Read();

        if (readChar == '\n' || (readChar == '\r' && stringReader.Peek() == '\n'))
        {
            // If it's a \r\n combo consume the \n part and throw it away.
            if (readChar == '\r')
            {
                stringReader.Read();
            }

            if (inQoutedString)
            {
                if (readChar == '\r')
                {
                    fieldBuilder.Append('\r');
                }
                fieldBuilder.Append('\n');
            }
            else
            {
                record.Add(fieldBuilder.ToString().TrimEnd());
                fieldBuilder = new StringBuilder();

                records.Add(record);
                record = new List<string>();

                inQoutedString = false;
            }
        }
        else if (fieldBuilder.Length == 0 && !inQoutedString)
        {
            if (char.IsWhiteSpace(readChar))
            {
                // Ignore leading whitespace
            }
            else if (readChar == '"')
            {
                inQoutedString = true;
            }
            else if (readChar == ',')
            {
                record.Add(fieldBuilder.ToString().TrimEnd());
                fieldBuilder = new StringBuilder();
            }
            else
            {
                fieldBuilder.Append(readChar);
            }
        }
        else if (readChar == ',')
        {
            if (inQoutedString)
            {
                fieldBuilder.Append(',');
            }
            else
            {
                record.Add(fieldBuilder.ToString().TrimEnd());
                fieldBuilder = new StringBuilder();
            }
        }
        else if (readChar == '"')
        {
            if (inQoutedString)
            {
                if (stringReader.Peek() == '"')
                {
                    stringReader.Read();
                    fieldBuilder.Append('"');
                }
                else
                {
                    inQoutedString = false;
                }
            }
            else
            {
                fieldBuilder.Append(readChar);
            }
        }
        else
        {
            fieldBuilder.Append(readChar);
        }
    }
    record.Add(fieldBuilder.ToString().TrimEnd());
    records.Add(record);

    return records;
}
Run Code Online (Sandbox Code Playgroud)

请注意,这不处理字段的边缘情况,这些字段没有被双引号括起来,但是meerley在其中有一个带引号的字符串.请参阅此文章以获得更好的扩展以及一些适当库的链接.


Jon*_*way 9

我同意@ NotMyself.FileHelpers经过了充分的测试,可以处理各种边缘情况,如果您自己动手,最终必须处理这些边缘情况.看看FileHelpers做了什么,只有你绝对确定(1)你永远不需要处理FileHelpers所做的边缘情况,或者(2)你喜欢写这种东西并打算当你必须解析这样的东西时,我会高兴极了:

1,"比尔","史密斯","主管","没有评论"

2,'德雷克',''奥马利',"看门人,

哎呀,我没有引用,我正在换新线!


Bri*_*ahy 6

我很无聊所以我修改了一些我写的东西.它尝试以OO方式封装解析,减少通过文件的迭代量,它只在顶层foreach迭代一次.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.IO;

namespace ConsoleApplication1
{
    class Program
    {

        static void Main(string[] args)
        {

            // usage:

            // note this wont run as getting streams is not Implemented

            // but will get you started

            CSVFileParser fileParser = new CSVFileParser();

            // TO Do:  configure fileparser

            PersonParser personParser = new PersonParser(fileParser);

            List<Person> persons = new List<Person>();
            // if the file is large and there is a good way to limit
            // without having to reparse the whole file you can use a 
            // linq query if you desire
            foreach (Person person in personParser.GetPersons())
            {
                persons.Add(person);
            }

            // now we have a list of Person objects
        }
    }

    public abstract  class CSVParser 
    {

        protected String[] deliniators = { "," };

        protected internal IEnumerable<String[]> GetRecords()
        {

            Stream stream = GetStream();
            StreamReader reader = new StreamReader(stream);

            String[] aRecord;
            while (!reader.EndOfStream)
            {
                  aRecord = reader.ReadLine().Split(deliniators,
                   StringSplitOptions.None);

                yield return aRecord;
            }

        }

        protected abstract Stream GetStream(); 

    }

    public class CSVFileParser : CSVParser
    {
        // to do: add logic to get a stream from a file

        protected override Stream GetStream()
        {
            throw new NotImplementedException();
        } 
    }

    public class CSVWebParser : CSVParser
    {
        // to do: add logic to get a stream from a web request

        protected override Stream GetStream()
        {
            throw new NotImplementedException();
        }
    }

    public class Person
    {
        public String Name { get; set; }
        public String Address { get; set; }
        public DateTime DOB { get; set; }
    }

    public class PersonParser 
    {

        public PersonParser(CSVParser parser)
        {
            this.Parser = parser;
        }

        public CSVParser Parser { get; set; }

        public  IEnumerable<Person> GetPersons()
        {
            foreach (String[] record in this.Parser.GetRecords())
            {
                yield return new Person()
                {
                    Name = record[0],
                    Address = record[1],
                    DOB = DateTime.Parse(record[2]),
                };
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Yaa*_*lis 5

CodeProject上有两篇文章为解决方案提供代码,一篇使用StreamReader,另一篇使用Microsoft Text Driver 导入CSV数据.


hel*_*dre 2

一个简单的好方法是打开文件,并将每一行读入数组、链表、您选择的数据结构中。不过,处理第一行时要小心。

这可能超出了您的理解范围,但似乎还有一种直接的方法可以使用连接字符串来访问它们。

为什么不尝试使用 Python 而不是 C# 或 VB?它有一个很好的 CSV 模块可供导入,可以为您完成所有繁重的工作。