LINQ to CSV library
2013-11-14 14:36
417 查看
by
Matt Perdeck12. 九月 2011 22:39
Download source and sample codeNuGet package
Contents
IntroductionRequirements
Installation
Quick Start
Write Overloads
Read Overloads
Reading Raw Data Rows
Deferred Reading
CsvFileDescription
CsvColumn Attribute
Error Handling
Introduction
This library makes it easy to use CSV files with LINQ queries. Its features include:Follows the
most common rules for CSV files. Correctly handles data fields that contain commas and line breaks.
In addition to comma, most delimiting characters can be used, including tab for tab delimited fields.
Can be used with an
IEnumarableof an anonymous class - which is often returned by a LINQ query.
Supports deferred reading.
Supports processing files with international date and number formats.
Supports different character encodings if you need them.
Recognizes a wide variety of date and number formats when reading files.
Provides fine control of date and number formats when writing files.
Robust error handling, allowing you to quickly find and fix problems in large input files.
Requirements
To compile the library, you need a C# 2008 compiler, such as Visual Studio 2008 or Visual C# 2008 Express Edition.To run the library code, you need to have the .NET 3.5 framework installed.
Installation
These instructions apply to the download with sources and sample code. The NuGet package installs itself.Download the zip file with the source code, and unzip in a directory.
Open the Code\LINQtoCSV.sln file in Visual Studio.
You'll find that the sources are organized in a solution, with these elements:
Project LINQtoCSV is the actual library.
Project SampleCode has the sample code shown in this article.
Project TestConsoleApplication is a working console application that exercises most of the features of the library. The code is heavily documented.
The directory TestFiles within the TestConsoleApplication project contains test files - both CSV and tab delimited, and with both US and international (Dutch) dates and numbers.
Compile the solution. This will produce a LINQtoCSV.dll file in the
Code\LINQtoCSV\bin directory. You'll need that file to use the library in your own projects.
Quick Start
Reading from a file
In your project, add a reference to the LINQtoCSV.dll you generated duringInstallation.The file will be read into an
IEnumerable<T>, where
Tis a data class that you define. The data records read from the file will be stored in objects of this data class. You could define a data class along these lines:
using LINQtoCSV; using System; class Product { [CsvColumn(Name = "ProductName", FieldIndex = 1)] public string Name { get; set; } [CsvColumn(FieldIndex = 2, OutputFormat = "dd MMM HH:mm:ss")] public DateTime LaunchDate { get; set; } [CsvColumn(FieldIndex = 3, CanBeNull = false, OutputFormat = "C")] public decimal Price { get; set; } [CsvColumn(FieldIndex = 4)] public string Country { get; set; } [CsvColumn(FieldIndex = 5)] public string Description { get; set; } }
With this definition, you could read into an
IEnumerable<Product>.
Although this example only uses properties, the library methods will recognize simple fields as well. Just make sure your fields/properties are public.
The optional
CsvColumnattribute allows you to specify whether a field/property is required, how it should be written to an output file, etc. Full details are availablehere.
Import the
LINQtoCSVnamespace at the top of the source file where you'll be reading the file:
using LINQtoCSV;
Create a
CsvFileDescriptionobject, and initialize it with details about the file that you're going to read. It will look like this:
CsvFileDescription inputFileDescription = new CsvFileDescription { SeparatorChar = ',', FirstLineHasColumnNames = true };
This allows you to specify what character is used to separate data fields (comma, tab, etc.), whether the first record in the file holds column names, and a lot more (full
details).
Create a
CsvContextobject:
CsvContext cc = new CsvContext();
It is this object that exposes the
Readand
Writemethods you'll use to read and write files.
Read the file into an
IEnumerable<T>using the
CsvContextobject's
Readmethod, like this:
IEnumerable<Product> products = cc.Read<Product>("products.csv", inputFileDescription);
This reads the file products.csv into the variable
products, which is of type
IEnumerable<Product>.
You can now access
productsvia a LINQ query, a
foreachloop, etc.:
var productsByName =
from p in products
orderby p.Name
select new { p.Name, p.LaunchDate, p.Price, p.Description };
// or ...foreach (Product item in products) { .... }
To make it easier to get an overview, here is the code again that reads from a file, but now in one go:
CsvFileDescription inputFileDescription = new CsvFileDescription { SeparatorChar = ',', FirstLineHasColumnNames = true };
CsvContext cc = new CsvContext();
IEnumerable<Product> products = cc.Read<Product>("products.csv", inputFileDescription);
// Data is now available via variable products.
var productsByName =
from p in products
orderby p.Name
select new { p.Name, p.LaunchDate, p.Price, p.Description };
// or ...foreach (Product item in products) { .... }
You'll find this same code in the SampleCode project in the
sources.
Writing to a file
This is very similar toreading a file.
In your project, add a reference to LINQtoCSV.dll.
The
Writemethod takes a
IEnumerable<T>and writes each object of type
Tin the
IEnumerable<T>as a data record to the file. The definition of your data class could look like this:
using LINQtoCSV; using System; class Product { [CsvColumn(Name = "ProductName", FieldIndex = 1)] public string Name { get; set; } [CsvColumn(FieldIndex = 2, OutputFormat = "dd MMM HH:mm:ss")] public DateTime LaunchDate { get; set; } [CsvColumn(FieldIndex = 3, CanBeNull = false, OutputFormat = "C")] public decimal Price { get; set; } [CsvColumn(FieldIndex = 4)] public string Country { get; set; } [CsvColumn(FieldIndex = 5)] public string Description { get; set; } }
The optional
CsvColumn attribute allows you to specify such things as what date and number formats to use when writing each data field. Details for all CsvColumn properties (
CanBeNull,
OutputFormat, etc.) are availablehere.
Although this example only uses properties, you can also use simple fields.
The
Writemethod will happily use an anonymous type for
T, so you can write the output of a LINQ query right to a file. In that case, you obviously won't define
Tyourself.Later
on, you'll see an example of this.
Import the
LINQtoCSVnamespace at the top of the source file where you'll be writing the file:
using LINQtoCSV;
Make sure the data is stored in an object that implements
IEnumerable<T>, such as a
List<T>, or the
IEnumerable<T>returned by the
Readmethod.
List<Product> products2 = new List<Product>(); // Fill the list with products // ...
Create aCsvFileDescription object, and initialize it with details about the file you will be writing, along these lines:
CsvFileDescription outputFileDescription = new CsvFileDescription { SeparatorChar = '\t', // tab delimited FirstLineHasColumnNames = false, // no column names in first record FileCultureName = "nl-NL" // use formats used in The Netherlands };
Create a
CsvContextobject:
CsvContext cc = new CsvContext();
Invoke the
Writemethod exposed by the
CsvContextobject to write the contents of your
IEnumerable<T>to a file:
cc.Write( products2, "products2.csv", outputFileDescription);
This writes the
Productobjects in the variable
products2to the file "products2.csv".
Here is the code again that writes a file, but now in one go:
List<Product> products2 = new List<Product>(); // Fill the list with products // ...
CsvFileDescription outputFileDescription = new CsvFileDescription { SeparatorChar = '\t', // tab delimited FirstLineHasColumnNames = false, // no column names in first record FileCultureName = "nl-NL" // use formats used in The Netherlands };
CsvContext cc = new CsvContext();
cc.Write( products2, "products2.csv", outputFileDescription);
Writing an IEnumerable of anonymous type
If you have a LINQ query producing anIEnumerableof anonymous type, writing that
IEnumerableto a file is no problem:
CsvFileDescription outputFileDescription = new CsvFileDescription { ..... }; CsvContext cc = new CsvContext(); // LINQ query returning IEnumerable of anonymous type // into productsNetherlands var productsNetherlands = from p in products where p.Country == "Netherlands" select new { p.Name, p.LaunchDate, p.Price, p.Description }; // Write contents of productsNetherlands to file cc.Write( productsNetherlands, "products-Netherlands.csv", outputFileDescription);
Here, a LINQ query selects all products for "Netherlands" from the variable
products, and returns an
IEnumerableholding objects of some anonymous type that has the fields
Name,
LaunchDate,
Price, and
Description. The
Writemethod then writes those objects to the fileproducts-Netherlands.csv.
CsvContext.Write Overloads
Write<T>(IEnumerable<T> values, string fileName)
Write<T>(IEnumerable<T> values, string fileName, CsvFileDescription fileDescription)
Write<T>(IEnumerable<T> values, TextWriter stream)
Write<T>(IEnumerable<T> values, TextWriter stream, CsvFileDescription fileDescription)
Some interesting facts about these overloads:
None of the overloads return a value.
Unlike the
Readmethod,
Writedoes not require that
Thas a parameterless constructor.
Overloads that take a stream write the data to the stream. Those that take a file name write the data to the file.
Overloads that do not take aCsvFileDescription object simply create one themselves, using the default values for the
CsvFileDescriptionproperties.
CsvContext.Read Overloads
Read<T>(string fileName)
Read<T>(string fileName, CsvFileDescription fileDescription)
Read<T>(StreamReader stream)
Read<T>(StreamReader stream, CsvFileDescription fileDescription)
Some interesting facts about these overloads:
Each overload returns an
IEnumerable<T>.
Tmust have a parameterless constructor. If you do not define a constructor for
T, the compiler will generate a parameterless constructor for you.
Overloads that take a stream read the data from the stream. Those that take a file name read the data from the file. However, see the section ondeferred
reading.
Overloads that do not take aCsvFileDescription object simply create one themselves, using the default values for the
CsvFileDescriptionproperties.
Reading Raw Data Rows
Sometimes it's easier to read the raw data fields from the CSV file, instead of having them processed into objects by the library. For example if different rows can have different formats, or if you don't know at compile time which field is going to holdwhat data.
You can make this happen by having your type T implement the interface
IDataRow. This interface is included in the library, so you don't have to write it yourself. It essentially just describes a collection of
DataRowItemobjects:
The
DataRowItemclass is also defined in the library. It describes each individual field within a data row:
public interface IDataRow { // Number of data row items in the row. int Count { get; } // Clear the collection of data row items. void Clear(); // Add a data row item to the collection. void Add(DataRowItem item); // Allows you to access each data row item with an array index, such as // row[i] DataRowItem this[int index] { get; set; } }
public class DataRowItem { ... // Line number of the field public int LineNbr { get { ... } } // Value of the field public string Value { get { ... } } }
public class DataRowItem { ... // Line number of the field public int LineNbr { get { ... } } // Value of the field public string Value { get { ... } } }
The line number is included in the
DataRowItemclass, because data rows can span multiple lines.
The easiest way to create a class that implements
IDataRowis to derive it from
List<DataRowItem>:
using LINQtoCSV; internal class MyDataRow : List<DataRowItem>, IDataRow { }
Now you can read the CSV file into a collection of
MyDataRowobjects:
IEnumerable<MyDataRow> products = cc.Read<MyDataRow>("products.csv", inputFileDescription);
You can then access each individual field within each data row:
foreach (MyDataRow dataRow in products) { string firstFieldValue = dataRow[0].Value; int firstFieldLineNbr = dataRow[0].LineNbr; string secondFieldValue = dataRow[1].Value; int secondFieldLineNbr = dataRow[1].LineNbr; ... }
Deferred Reading
Here is how theReadoverloads implement deferred reading:
When you invoke the
Readmethod (which returns an
IEnumerable<T>), no data is read yet. If using a file, the file is not yet opened.
When the Enumerator is retrieved from the
IEnumerable<T>(for example, when starting a
foreachloop), the file is opened for reading. If using a stream, the stream is rewound (seek to start of the stream).
Each time you retrieve a new object from the Enumerator (for example, while looping through a
foreach), a new record is read from the file or stream.
When you close the Enumerator (for example, when a
foreachends or when you break out of it), the file is closed. If using a stream, the stream is left unchanged.
This means that:
If reading from a file, the file will be open for reading while you're accessing the
IEnumerable<T>in a
foreachloop.
The file can be updated in between accesses. You could access the
IEnumerable<T>in a
foreachloop, then update the file, then access the
IEnumerable<T>again in a
foreachloop to pick up the new data, etc. You only need to call
Readonce at the beginning, to get the
IEnumerable<T>.
CsvFileDescription
TheReadand
Writemethods need some details about the file they are reading or writing, such as whether the first record contains column names.
As shown in the
Reading from a file and
Writing to a file examples, you put those details in an object of type
CsvFileDescription, which you then pass to the
Reador
Writemethod. This prevents lengthy parameter lists, and allows you to use the same details for multiple files.
A
CsvFileDescriptionobject has these properties:
SeparatorChar
QuoteAllFields
FirstLineHasColumnNames
EnforceCsvColumnAttribute
FileCultureName
TextEncoding
DetectEncodingFromByteOrderMarks
MaximumNbrExceptions
SeparatorChar
Type: | char |
Default: | ',' |
Applies to: | Reading and Writing |
Example:
CsvFileDescription fd = new CsvFileDescription(); fd.SeparatorChar = '\t'; // use tab delimited file CsvContext cc = new CsvContext(); cc.Write(data, "file.csv", fd);
The character used to separate fields in the file. This would be a comma for CSV files, or a '\t' for a tab delimited file.
You can use any character you like, except for white space characters or the double quote (").
QuoteAllFields
Type: | bool |
Default: | false |
Applies to: | Writing only |
Example:
fd.QuoteAllFields = true; // forces quotes around all fields
When
false,
Writeonly puts quotes around data fields when needed, to avoid confusion - for example, when the field contains the
SeparatorCharor a line break.
When
true,
Writesurrounds all data fields with quotes.
FirstLineHasColumnNames
Type: | bool |
Default: | true |
Applies to: | Reading and Writing |
Example:
fd.FirstLineHasColumnNames = false; // first record does not have column headers
When reading a file, tells
Readwhether to interpret the data fields in the first record in the file as column headers.
When writing a file, tells
Writewhether to write column headers as the first record of the file.
EnforceCsvColumnAttribute
Type: | bool |
Default: | false |
Applies to: | Reading and Writing |
Example:
fd.EnforceCsvColumnAttribute = true; // only use fields with [CsvColumn] attribute
When
true,
Readonly reads data fields into public fields and properties with the
[CsvColumn]attribute, ignoring all other fields and properties. And,
Writeonly writes the contents of public fields
and properties with the
[CsvColumn]attribute.
When
false, all public fields and properties are used.
FileCultureName
Type: | string |
Default: | current system setting |
Applies to: | Reading and Writing |
Example:
fd.FileCultureName = "en-US"; // use US style dates and numbers
Different cultures use different ways to write dates and numbers. 23 May 2008 is 5/23/2008 in the United States (en-US) and 23/5/2008 in Germany (de-DE). Use the
FileCultureNamefield to tell
Readhow to interpret the dates and numbers
it reads from the file, and to tell
Writehow to write dates and numbers to the file.
By default, the library uses the current language/country setting on your system. So, if your system uses French-Canadian (fr-CA), the library uses that culture unless you override it with
FileCultureName.
The library uses the same culture names as the .NET "
CultureInfo" class (full list of names).
TextEncoding
Type: | Encoding |
Default: | Encoding.UTF8 |
Applies to: | Reading and Writing |
Example:
fd.TextEncoding = Encoding.Unicode; // use Unicode character encoding
If the files that you read or write are in English, there is no need to set
TextEncoding.
However, if you use languages other than English, the way the characters in your files are encoded may be an issue. You will want to make sure that the encoding used by the library matches the encoding used by any other programs (editors, spreadsheets) that
access your files.
Specifically, if you write files with the Euro symbol, you may need to use Unicode encoding, as shown in the example.
DetectEncodingFromByteOrderMarks
Type: | bool |
Default: | true |
Applies to: | Reading only |
Example:
fd.DetectEncodingFromByteOrderMarks = false; // suppress encoding detection
Related to
TextEncoding. The default normally works fine.
Tells
Readwhether to detect the encoding of the input file by looking at the first three bytes of the file. Otherwise, it uses the encoding given in the
TextEncodingproperty.
MaximumNbrExceptions
Type: | int |
Default: | 100 |
Applies to: | Reading only |
Example:
fd.MaximumNbrExceptions = -1; // always read entire file before throwing AggregatedException
Sets the maximum number of exceptions that will be aggregated into an
AggregatedException.
To not have any limit and read the entire file no matter how many exceptions you get, set
AggregatedExceptionto -1.
For details about aggregated exceptions, see the
error handling section.
CsvColumn Attribute
As shown in theReading from a file and
Writing to a file examples, you can decorate the public fields and properties of your data class with the
CsvColumnattribute to specify such things as the output format for date and number fields.
Use of the
CsvColumnattribute is optional. As long as the
EnforceCsvColumnAttribute property of theCsvFileDescription object you pass into
Reador
Writeis
false, those methods will look at all public fields and properties in the data class. They will then simply use the defaults shown with each
CsvColumn
property below.
The
CsvColumnattribute has these properties:
Name
CanBeNull
NumberStyle
OutputFormat
FieldIndex
Name
Type: | string |
Default: | Name of the field or property |
Applies to: | Reading and Writing |
Example:
[CsvColumn(Name = "StartDate")] public DateTime LaunchDate { get; set; }
The
Readand
Writemethods normally assume that the data fields in the file have the same names as the corresponding fields or properties in the class. Use the
Nameproperty to specify another name for the data field.
CanBeNull
Type: | bool |
Default: | true |
Applies to: | Reading only |
[CsvColumn(CanBeNull = false)] public DateTime LaunchDate { get; set; }
If
false, and a record in the input file does not have a value for this field or property, then the
Readmethod generates aMissingRequiredFieldException
exception.
FieldIndex
Type: | bool |
Default: | Int32.MaxValue |
Applies to: | Reading only |
Example:
[CsvColumn(FieldIndex = 1)] public DateTime LaunchDate { get; set; }
This property is used for both reading and writing, but in slightly different ways.
Reading - The
Readmethod needs to somehow associate data fields in the input file with field and properties in the data class. If the file has column names in the first record, that's easy -
Readsimply matches
the column names with the names of the fields and properties in the data class.
However, if the file does not have column names in the first record,
Readneeds to look at the order of the data fields in the data records to match them with the fields and properties in the data class. Unfortunately though, the .NET framework
does not provide a way to reliably retrieve that order from the class definition. So, you have to specify which field/property comes before which field/property by giving the fields and properties a
CsvColumnattribute with the
FieldIndex
property.
The
FieldIndexs do not have to start at 1. They don't have to be consecutive. The
Readand
Writemethods will simply assume that a field/property comes before some other field/property if its
FieldIndexis
lower.
Writing - The
Writemethod uses the
FieldIndexof each field or property to figure out in what order to write the data fields to the output file. Field and properties without
FieldIndexget written last,
in random order.
NumberStyle
Type: | NumberStyles |
Default: | NumberStyles.Any |
Applies to: | Reading of numeric fields only |
Example:
[CsvColumn(NumberStyle = NumberStyles.HexNumber)] public DateTime LaunchDate { get; set; }
Allows you to determine what number styles are allowed in the input file (list of options).
By default, all styles are permitted, except for one special case. In order to accept hexadecimal numbers that do not start with 0x, use
NumberStyles.HexNumber, as shown in the example.
OutputFormat
Type: | string |
Default: | "G" |
Applies to: | Writing only |
Example:
[CsvColumn(OutputFormat = "dd MMM yy")] public DateTime LaunchDate { get; set; }
Lets you set the output format of numbers and dates/times. The default "G" format works well for both dates and numbers most of the time.
When writing a date/time or number field, the
Writemethod first determines the type of the field (
DateTime,
decimal,
double, etc.) and then calls the
ToStringmethod for that type, with the given
OutputFormat. So, in the example above, if
LaunchDateis 23 November 2008, the field written to the file will be "23 Nov 08".
With many formats, the final result depends on the language/country of the file, as set in theFileCultureName property of theCsvFileDescription
object. So, if
LaunchDateis 23 November 2008 and you specify the short date format:
[CsvColumn(OutputFormat = "d")] public DateTime LaunchDate { get; set; }
Then, the final value written to the output file will be "11/23/08" if you use US dates (
FileCultureNameis set to "en-US"), but "23/11/08" if you use German dates (
FileCultureNameis set to "de-DE").
Format Codes for DateTime
Standard Numeric Format Strings
Custom Numeric Format Strings
Error Handling
ExceptionLINQtoCSVException
BadStreamException
CsvColumnAttributeRequiredException
DuplicateFieldIndexException
RequiredButMissingFieldIndexException
ToBeWrittenButMissingFieldIndexException
NameNotInTypeException
MissingCsvColumnAttributeException
TooManyDataFieldsException
TooManyNonCsvColumnDataFieldsException
MissingFieldIndexException
MissingRequiredFieldException
WrongDataFormatException
AggregatedException
When the
Readand
Writemethods detect an error situation, they throw an exception with all information you need to solve the problem. As you would expect, all exceptions are derived from the .NET classException.
Retrieving error information
In addition to such properties as
StackTraceand
Message, the
Exceptionclass exposes the
Data property. The
Readand
Writemethods use that property to provide exception information in a way that is easy for your code to read, while they provide error messages targeted at humans via the
Messageproperty.
The description for each exception (further below) shows what information is stored in the
Dataproperty.
Aggregating exceptions
When the
Readmethod detects an error while reading data from a file, it does not throw an exception right away, but stores it in a list of type
List<Exception>. Then, after it has processed the file, it throws a single exception
of typeAggregatedException, with the list of exceptions in its
Data["InnerExceptionsList"]property. This allows you
to fix all problems with an input file in one go, instead of one by one.
You can limit the number of exceptions that get aggregated this way by setting theMaximumNbrExceptions property of theCsvFileDescription
object that you pass to the
Readmethod. By default,
MaximumNbrExceptionsis set to 100. When the limit is reached, the
AggregatedExceptionis thrown right away, with the list of exceptions aggregated so far.
Not all exceptions get aggregated! Before
Readstarts reading data from a file, it first processes column names,
CsvColumnattributes, etc. If something goes wrong during that preliminary stage, it throws an exception right away.
Deferred reading
Keep in mind that due to
deferred reading, you can get exceptions not only when you invoke the
Readmethod, but also when you access the
IEnumerable<T>that is returned by the
Readmethod.
Example
The following code reads a file and processes exceptions. To show how to use the
Dataproperty, it includes some special processing for the
DuplicateFieldIndexException- thrown when the
Readand
Writemethods detect two fields or properties with the sameFieldIndex.
public static void ShowErrorMessage(string errorMessage)
{
// show errorMessage to user
// .....
}
public static void ReadFileWithExceptionHandling()
{
try
{
CsvContext cc = new CsvContext();
CsvFileDescription inputFileDescription = new CsvFileDescription
{
MaximumNbrExceptions = 50
// limit number of aggregated exceptions to 50
};
IEnumerable<Product> products =
cc.Read<Product>("products.csv", inputFileDescription);
// Do data processing
// ...........
}
catch(AggregatedException ae)
{
// Process all exceptions generated while processing the file
List<Exception> innerExceptionsList =
(List<Exception>)ae.Data["InnerExceptionsList"];
foreach (Exception e in innerExceptionsList)
{
ShowErrorMessage(e.Message);
}
}
catch(DuplicateFieldIndexException dfie)
{
// name of the class used with the Read method - in this case "Product"
string typeName = Convert.ToString(dfie.Data["TypeName"]);
// Names of the two fields or properties that have the same FieldIndex
string fieldName = Convert.ToString(dfie.Data["FieldName"]);
string fieldName2 = Convert.ToString(dfie.Data["FieldName2"]);
// Actual FieldIndex that the two fields have in common
int commonFieldIndex = Convert.ToInt32(dfie.Data["Index"]);
// Do some processing with this information
// .........
// Inform user of error situation
ShowErrorMessage(dfie.Message);
}
catch(Exception e)
{
ShowErrorMessage(e.Message);
}
}
{
// show errorMessage to user
// .....
}
public static void ReadFileWithExceptionHandling()
{
try
{
CsvContext cc = new CsvContext();
CsvFileDescription inputFileDescription = new CsvFileDescription
{
MaximumNbrExceptions = 50
// limit number of aggregated exceptions to 50
};
IEnumerable<Product> products = cc.Read<Product>("products.csv", inputFileDescription);
// Do data processing
// ...........
}
catch(AggregatedException ae)
{
// Process all exceptions generated while processing the file
List<Exception> innerExceptionsList =
(List<Exception>)ae.Data["InnerExceptionsList"];
foreach (Exception e in innerExceptionsList)
{
ShowErrorMessage(e.Message);
}
}
catch(DuplicateFieldIndexException dfie)
{
// name of the class used with the Read method - in this case "Product"
string typeName = Convert.ToString(dfie.Data["TypeName"]);
// Names of the two fields or properties that have the same FieldIndex
string fieldName = Convert.ToString(dfie.Data["FieldName"]);
string fieldName2 = Convert.ToString(dfie.Data["FieldName2"]);
// Actual FieldIndex that the two fields have in common
int commonFieldIndex = Convert.ToInt32(dfie.Data["Index"]);
// Do some processing with this information
// .........
// Inform user of error situation
ShowErrorMessage(dfie.Message);
}
catch(Exception e)
{
ShowErrorMessage(e.Message);
}
}
BadStreamException
This exception exposes the same properties asException.
Thrown when a stream is passed to
Read, which is either
null, or does not support
Seek. The stream has to support
Seek, otherwise it cannot be rewound when the
IEnumarablereturned by
Readis accessed.
CsvColumnAttributeRequiredException
This exception exposes the same properties asException.
Thrown when the
CsvFileDescriptionobject that has been passed to
Readhas bothFirstLineHasColumnNames
and
EnforceCsvColumnAttribute set to
false.
If there are no column names in the file, then
Readrelies on the
FieldIndexof each field or property in the data class to match them with the data fields in the file. However, if
EnforceCsvColumnAttributeis
false,
that implies that fields or properties without the
CsvColumnattribute can also be used to accept data, while they do not have a
FieldIndex.
DuplicateFieldIndexException
Additional Properties - This exception exposes the same properties asException, plus these additional properties:Property | Type | Description |
Data["TypeName"] | string | Name of the class with the offending fields/properties |
Data["FieldName"] | string | Fields or properties with a duplicate FieldIndex |
Data["FieldName2"] | ||
Data["Index"] | int | Common FieldIndex |
FieldIndex.
RequiredButMissingFieldIndexException
Additional Properties - This exception exposes the same properties asException, plus these additional properties:Property | Type | Description |
Data["TypeName"] | string | Name of the class with the offending field/property |
Data["FieldName"] | string | Field or property without FieldIndex |
false),
each required field (CanBeNull attribute set to
false) must have aFieldIndex
attribute, otherwise it cannot be read from the file.
ToBeWrittenButMissingFieldIndexException
Additional Properties - This exception exposes the same properties asException, plus these additional properties:Property | Type | Description |
Data["TypeName"] | string | Name of the class with the offending field/property |
Data["FieldName"] | string | Field or property without FieldIndex |
So, when the
Writemethod is given aCsvFileDescription with
FirstLineHasColumnNames as
false, and it finds a field or property that doesn't have a
FieldIndex, it throws a
ToBeWrittenButMissingFieldIndexException.
NameNotInTypeException
Additional Properties - This exception exposes the same properties asException, plus these additional properties:Property | Type | Description |
Data["TypeName"] | string | Name of the class missing the field/property |
Data["FieldName"] | string | Field or property that isn't found |
Data["FileName"] | string | Name of the input file |
Readmethod is given aCsvFileDescription with
FirstLineHasColumnNames as
true, and one of the column names in the first record in the file does not match a field or property, it throws a
NameNotInTypeException.
MissingCsvColumnAttributeException
Additional Properties - This exception exposes the same properties asException, plus these additional properties:Property | Type | Description |
Data["TypeName"] | string | Name of the class with the offending field/property |
Data["FieldName"] | string | Field or property without CsvColumnattribute |
Data["FileName"] | string | Name of the input file |
Readmethod may throw this exception when it is given aCsvFileDescription with both
FirstLineHasColumnNames and
EnforceCsvColumnAttribute as
true. When
Readreads the column names from the first record, one of those column names may match a field or property that doesn't have a
CsvColumnattribute, even though only
fields and properties with a
CsvColumnattribute can be used. When that happens,
Readthrows a
MissingCsvColumnAttributeException.
TooManyDataFieldsException
Additional Properties - This exception exposes the same properties asException, plus these additional properties:Property | Type | Description |
Data["TypeName"] | string | Name of the data class |
Data["LineNbr"] | int | Line in the input file with an excess data field |
Data["FileName"] | string | Name of the input file |
TooManyNonCsvColumnDataFieldsException
Additional Properties - This exception exposes the same properties asException, plus these additional properties:Property | Type | Description |
Data["TypeName"] | string | Name of the data class |
Data["LineNbr"] | int | Line in the input file with an excess data field |
Data["FileName"] | string | Name of the input file |
CsvColumnattribute are used (
Readis given aCsvFileDescription
with
EnforceCsvColumnAttribute as
true), and a record in the input file has more data fields than there are fields and properties with the
CsvColumnattribute, a
TooManyNonCsvColumnDataFieldsExceptionis thrown.
MissingFieldIndexException
Additional Properties - This exception exposes the same properties asException, plus these additional properties:Property | Type | Description |
Data["TypeName"] | string | Name of the data class |
Data["LineNbr"] | int | Line with offending field |
Data["FileName"] | string | Name of the input file |
Readis given aCsvFileDescription withFirstLineHasColumnNames
as
false), then
Readrelies on theFieldIndex of the fields and properties in the data class to match
them with the data fields in the file.
When a record in the input file has more data fields than there are fields and properties in the data class with a
FieldIndex, then a
MissingFieldIndexExceptionis thrown.
MissingRequiredFieldException
Additional Properties - This exception exposes the same properties asException, plus these additional properties:Property | Type | Description |
Data["TypeName"] | string | Name of the class with the required field/property |
Data["FieldName"] | string | Name of the required field/property |
Data["LineNbr"] | int | Line where missing field should have been |
Data["FileName"] | string | Name of the input file |
attribute set to
false).
Difference between null and empty string
Empty strings and strings consisting of only white space need to be surrounded by quotes, so they are recognized as something other than
null.
These input lines both have the data fields "abc", null, and "def":
abc,,def abc, ,def
While this line has the data fields "abc", followed by the empty string, followed by "def":
abc,"",def
and this line has the data fields "abc", followed by a string with three spaces, followed by "def":
abc," ",def
WrongDataFormatException
Additional Properties - This exception exposes the same properties asException, plus these additional properties:Property | Type | Description |
Data["TypeName"] | string | Name of the class with the field/property |
Data["FieldName"] | string | Name of the field/property |
Data["FieldValue"] | string | The offending data value |
Data["LineNbr"] | int | Line with offending data value |
Data["FileName"] | string | Name of the input file |
AggregatedException
Additional Properties - This exception exposes the same properties asException, plus these additional properties:Property | Type | Description |
Data["TypeName"] | string | Name of the data class used by Read |
Data["FileName"] | string | Name of the input file |
Data["InnerExceptionsList"] | List<Exception> | List of Exceptions |
转自:http://www.aspnetperformance.com/post/LINQ-to-CSV-library.aspx
相关文章推荐
- PHPExcelReader 读取excel文件
- NSLog函数重写
- JAVA单例模式的优缺点
- MyEclipse取消验证Js的两种途径.
- linux sed命令
- 2.29 Listening and Reacting to Keyboard Notifications
- Oracle DB 存储增强
- WCF服务对于处理客户端连接的一点思考
- c++动态陷阱
- bash 编程应用及调试
- redis安装
- 全差分运放
- 创建自己的taglib 并打包入jar
- opengl中添加纹理
- ubuntu12.04下nfs安装、配置、测试 .
- 创建自己的taglib 并打包入jar
- 1817[校园歌手大赛]
- 简单介绍吸塑包装的原材料
- JavaScript 开发者经常忽略或误用的七个基础知识点
- [iOS编程-XCode Debug忽略SIGPIPE信号