diff --git a/docs/getting-started/index.html b/docs/getting-started/index.html index 4df2d05e4..75d04f81a 100644 --- a/docs/getting-started/index.html +++ b/docs/getting-started/index.html @@ -29,7 +29,7 @@

Package Manager Consol 2,two

In this case, the names are lower case. We want our property names to be Pascal Case, so we can just change how our properties match against the header names.

var config = new CsvConfiguration(CultureInfo.InvariantCulture)
 {
-    PrepareHeaderForMatch = (string header, int index) => header.ToLower(),
+    PrepareHeaderForMatch = args => args.Header.ToLower(),
 };
 using (var reader = new StreamReader("path\\to\\file.csv"))
 using (var csv = new CsvReader(reader, config))
@@ -135,4 +135,4 @@ 

Package Manager Consol allows you to write more things in the header if you need to. WriteRecord also will not advance you to the next row to give you the ability to write multiple objects or use WriteField to write individual fields.


-
© 2009-2020 Josh Close
\ No newline at end of file +
© 2009-2020 Josh Close
\ No newline at end of file diff --git a/docs/getting-started/routeInfo.json b/docs/getting-started/routeInfo.json index 6796b7ca7..25896f138 100644 --- a/docs/getting-started/routeInfo.json +++ b/docs/getting-started/routeInfo.json @@ -1 +1 @@ -{"template":"__react_static_root__/src/pages/documentation","sharedHashesByProp":{},"data":{"className":"getting-started","data":"# Getting Started\r\n\r\n## Installation\r\n
\r\n\r\n### Package Manager Console\r\n\r\n```\r\nPM> Install-Package CsvHelper\r\n```\r\n\r\n### .NET CLI Console\r\n\r\n```\r\n> dotnet add package CsvHelper\r\n```\r\n\r\n## Prerequisites\r\n\r\nThere is some basic .NET knowledge that is implied when using this documentation. Please look over the prequisites to make sure you have an\r\nunderstanding of them. [Prerequisites](/examples/prerequisites)\r\n\r\n## CultureInfo\r\n\r\nCsvHelper requires you to specify the `CultureInfo` that you want to use. The culture is used to determine the default delimiter, default line ending, and formatting when type converting. You can change the configuration of any of these too if you like. Choose the appropriate culture for your data. `InvariantCulture` will be the most portable for writing a file and reading it back again, so that will be used in most of the examples.\r\n\r\n## Newlines\r\n\r\nBy default, CsvHelper will follow [RFC 4180](https://tools.ietf.org/html/rfc4180#page-2) and use `\\r\\n` for writing newlines no matter what operating system\r\nyou are running on. CsvHelper can read `\\r\\n`, `\\r`, or `\\n` without any configuration changes. If you want to reaad or write in a non-standard format, you can\r\nchange the configuration for `NewLine`.\r\n\r\n```cs\r\nvar config = new CsvConfiguration(CultureInfo.InvariantCulture)\r\n{\r\n\tNewLine = Environment.NewLine,\r\n};\r\n```\r\n\r\n## Reading a CSV File\r\n
\r\n\r\nLet's say we have CSV file that looks like this.\r\n\r\n```\r\nId,Name\r\n1,one\r\n2,two\r\n```\r\n\r\nAnd a class definition that looks like this.\r\n\r\n```cs\r\npublic class Foo\r\n{\r\n\tpublic int Id { get; set; }\r\n\tpublic string Name { get; set; }\r\n}\r\n```\r\n\r\nIf our class property names match our CSV file header names, we can read the file without any configuration.\r\n\r\n```cs\r\nusing (var reader = new StreamReader(\"path\\\\to\\\\file.csv\"))\r\nusing (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))\r\n{\r\n\tvar records = csv.GetRecords();\r\n}\r\n```\r\n\r\nThe `GetRecords` method will return an `IEnumerable` that will `yield` records.\r\nWhat this means is that only a single record is returned at a time as you iterate the records.\r\nThat also means that only a small portion of the file is read into memory. Be careful though.\r\nIf you do anything that executes a LINQ projection, such as calling `.ToList()`, the entire file\r\nwill be read into memory. `CsvReader` is forward only, so if you want to run any LINQ queries\r\nagainst your data, you'll have to pull the whole file into memory. Just know that is what you're doing.\r\n\r\nLet's say our CSV file names are a little different than our class properties and we don't want to\r\nmake our properties match.\r\n\r\n```\r\nid,name\r\n1,one\r\n2,two\r\n```\r\n\r\nIn this case, the names are lower case. We want our property names to be Pascal Case, so we can\r\njust change how our properties match against the header names.\r\n\r\n```cs\r\nvar config = new CsvConfiguration(CultureInfo.InvariantCulture)\r\n{\r\n\tPrepareHeaderForMatch = (string header, int index) => header.ToLower(),\r\n};\r\nusing (var reader = new StreamReader(\"path\\\\to\\\\file.csv\"))\r\nusing (var csv = new CsvReader(reader, config))\r\n{\r\n\tvar records = csv.GetRecords();\r\n}\r\n```\r\n\r\nUsing the configuration `PrepareHeaderForMatch`, we're able to change how the header matching\r\nis done against the property name. Both the header and the property name are ran through the\r\n`PrepareHeaderForMatch` function. When the reader needs to find the property to set for the\r\nheader, they will now match. You can use this function to do other things such as remove\r\nwhitespace or other characters.\r\n\r\nLet's say out CSV file doesn't have a header at all.\r\n\r\n```\r\n1,one\r\n2,two\r\n```\r\n\r\nFirst we need to tell the reader that there is no header record, using configuration.\r\n\r\n```cs\r\nvar config = new CsvConfiguration(CultureInfo.InvariantCulture)\r\n{\r\n\tHasHeaderRecord = false,\r\n};\r\nusing (var reader = new StreamReader(\"path\\\\to\\\\file.csv\"))\r\nusing (var csv = new CsvReader(reader, config))\r\n{\r\n\tvar records = csv.GetRecords();\r\n}\r\n```\r\n\r\nCsvReader will use the position of the properties in the class as the index position. There is an\r\nissue with this though. [You can't rely on the ordering of class members in .NET](https://blogs.msdn.microsoft.com/haibo_luo/2006/07/10/member-order-returned-by-getfields-getmethods/).\r\nWe can solve this by mapping the property to a position in the CSV file.\r\n\r\nOne way to do this is with attribute mapping.\r\n\r\n```cs\r\npublic class Foo\r\n{\r\n\t[Index(0)]\r\n\tpublic int Id { get; set; }\r\n\r\n\t[Index(1)]\r\n\tpublic string Name { get; set; }\r\n}\r\n```\r\n\r\nThe `IndexAttribute` allows you to specify which position the CSV field is that you want to use\r\nfor the property.\r\n\r\nYou can also map by name. Let's use our lower case header example from before and see how we can\r\nuse attributes instead of changing the header matching.\r\n\r\n```cs\r\npublic class Foo\r\n{\r\n\t[Name(\"id\")]\r\n\tpublic int Id { get; set; }\r\n\r\n\t[Name(\"name\")]\r\n\tpublic string Name { get; set; }\r\n}\r\n```\r\n\r\n[There are many other attributes you can use also.](/api/CsvHelper.Configuration.Attributes)\r\n\r\nWhat if we don't have control over the class we want to map to so we can't add attributes to it?\r\nIn this case, we can use a fluent `ClassMap` to do the mapping.\r\n\r\n```cs\r\npublic class FooMap : ClassMap\r\n{\r\n\tpublic FooMap()\r\n\t{\r\n\t\tMap(m => m.Id).Name(\"id\");\r\n\t\tMap(m => m.Name).Name(\"name\");\r\n\t}\r\n}\r\n```\r\n\r\nTo use the mapping, we need to register it in the context.\r\n\r\n```cs\r\nusing (var reader = new StreamReader(\"path\\\\to\\\\file.csv\"))\r\nusing (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))\r\n{\r\n\tcsv.Context.RegisterClassMap();\r\n\tvar records = csv.GetRecords();\r\n}\r\n```\r\n\r\nCreating a class map is the recommended way of mapping files in CsvHelper because it's a\r\nlot more powerful.\r\n\r\nYou can also read rows by hand.\r\n\r\n```cs\r\nusing (var reader = new StreamReader(\"path\\\\to\\file.csv\"))\r\nusing (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))\r\n{\r\n\tcsv.Read();\r\n\tcsv.ReadHeader();\r\n\twhile (csv.Read())\r\n\t{\r\n\t\tvar record = csv.GetRecord();\r\n\t\t// Do something with the record.\r\n\t}\r\n}\r\n```\r\n\r\n`Read` will advance row. `ReadHeader` will read the row into CsvHelper as the header values.\r\nSeparating `Read` and `ReadHeader` allows you to do other things with the header row before\r\nmoving onto the next row. `GetRecord` also does not advance the reader to allow you to do\r\nother things with the row you might need to do. You may need to `GetField` for a single field\r\nor maybe call `GetRecord` multiple times to fill more than one object.\r\n\r\n\r\n## Writing a CSV File\r\n\r\nNow let's look at how we can write CSV files. It's basically the same thing, but in reverse order.\r\n\r\nLet's use the same class definition as before.\r\n\r\n```cs\r\npublic class Foo\r\n{\r\n\tpublic int Id { get; set; }\r\n\tpublic string Name { get; set; }\r\n}\r\n```\r\n\r\nAnd we have a set of records like this.\r\n\r\n```cs\r\nvar records = new List\r\n{\r\n\tnew Foo { Id = 1, Name = \"one\" },\r\n\tnew Foo { Id = 2, Name = \"two\" },\r\n};\r\n```\r\n\r\nWe can write the records to a file without any configuration.\r\n\r\n```cs\r\nusing (var writer = new StreamWriter(\"path\\\\to\\\\file.csv\"))\r\nusing (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))\r\n{\r\n\tcsv.WriteRecords(records);\r\n}\r\n```\r\n\r\nThe `WriteRecords` method will write all the records to the file. After you are done writing,\r\nyou should call `writer.Flush()` to ensure that all the data in the writer's internal buffer\r\nhas been flushed to the file. Once a `using` block has exited, the writer is automatically\r\nflushed, so we don't have to explicitly do it here. It's recommended to always wrap any\r\n`IDisposable` object with `using` blocks. The object will dispose of itself (and in our case\r\nflush too) as soon as possible after the `using` block has exited.\r\n\r\nRemember how we can't rely on property order in .NET? If we are writing a class that has a header,\r\nit doesn't matter, as long as we are reading using the headers later. If we want to position\r\nthe headers in the CSV file, we need to specify an index to guarantee it's order. It's\r\nrecommended to always set an index when writing.\r\n\r\n```cs\r\npublic class FooMap : ClassMap\r\n{\r\n\tpublic FooMap()\r\n\t{\r\n\t\tMap(m => m.Id).Index(0).Name(\"id\");\r\n\t\tMap(m => m.Name).Index(1).Name(\"name\");\r\n\t}\r\n}\r\n```\r\n\r\nYou can also write rows by hand.\r\n\r\n```cs\r\nusing (var writer = new StreamWriter(\"path\\\\to\\\\file.csv\"))\r\nusing (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))\r\n{\r\n\tcsv.WriteHeader();\r\n\tcsv.NextRecord();\r\n\tforeach (var record in records)\r\n\t{\r\n\t\tcsv.WriteRecord(record);\r\n\t\tcsv.NextRecord();\r\n\t}\r\n}\r\n```\r\n\r\n`WriteHeader` will not advance you to the next row. Separating `NextRecord` from `WriteHeader`\r\nallows you to write more things in the header if you need to. `WriteRecord` also will not\r\nadvance you to the next row to give you the ability to write multiple objects or use\r\n`WriteField` to write individual fields.\r\n\r\n
\r\n","toc":{"title":"Getting Started","path":"getting-started","children":[{"title":"Installation","path":"getting-started#installation"},{"title":"CultureInfo","path":"getting-started#cultureinfo"},{"title":"Newlines","path":"getting-started#newlines"},{"title":"Reading a CSV File","path":"getting-started#reading-a-csv-file"},{"title":"Writing a CSV File","path":"getting-started#writing-a-csv-file"}]}},"path":"getting-started"} +{"template":"__react_static_root__/src/pages/documentation","sharedHashesByProp":{},"data":{"className":"getting-started","data":"# Getting Started\r\n\r\n## Installation\r\n
\r\n\r\n### Package Manager Console\r\n\r\n```\r\nPM> Install-Package CsvHelper\r\n```\r\n\r\n### .NET CLI Console\r\n\r\n```\r\n> dotnet add package CsvHelper\r\n```\r\n\r\n## Prerequisites\r\n\r\nThere is some basic .NET knowledge that is implied when using this documentation. Please look over the prequisites to make sure you have an\r\nunderstanding of them. [Prerequisites](/examples/prerequisites)\r\n\r\n## CultureInfo\r\n\r\nCsvHelper requires you to specify the `CultureInfo` that you want to use. The culture is used to determine the default delimiter, default line ending, and formatting when type converting. You can change the configuration of any of these too if you like. Choose the appropriate culture for your data. `InvariantCulture` will be the most portable for writing a file and reading it back again, so that will be used in most of the examples.\r\n\r\n## Newlines\r\n\r\nBy default, CsvHelper will follow [RFC 4180](https://tools.ietf.org/html/rfc4180#page-2) and use `\\r\\n` for writing newlines no matter what operating system\r\nyou are running on. CsvHelper can read `\\r\\n`, `\\r`, or `\\n` without any configuration changes. If you want to reaad or write in a non-standard format, you can\r\nchange the configuration for `NewLine`.\r\n\r\n```cs\r\nvar config = new CsvConfiguration(CultureInfo.InvariantCulture)\r\n{\r\n\tNewLine = Environment.NewLine,\r\n};\r\n```\r\n\r\n## Reading a CSV File\r\n
\r\n\r\nLet's say we have CSV file that looks like this.\r\n\r\n```\r\nId,Name\r\n1,one\r\n2,two\r\n```\r\n\r\nAnd a class definition that looks like this.\r\n\r\n```cs\r\npublic class Foo\r\n{\r\n\tpublic int Id { get; set; }\r\n\tpublic string Name { get; set; }\r\n}\r\n```\r\n\r\nIf our class property names match our CSV file header names, we can read the file without any configuration.\r\n\r\n```cs\r\nusing (var reader = new StreamReader(\"path\\\\to\\\\file.csv\"))\r\nusing (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))\r\n{\r\n\tvar records = csv.GetRecords();\r\n}\r\n```\r\n\r\nThe `GetRecords` method will return an `IEnumerable` that will `yield` records.\r\nWhat this means is that only a single record is returned at a time as you iterate the records.\r\nThat also means that only a small portion of the file is read into memory. Be careful though.\r\nIf you do anything that executes a LINQ projection, such as calling `.ToList()`, the entire file\r\nwill be read into memory. `CsvReader` is forward only, so if you want to run any LINQ queries\r\nagainst your data, you'll have to pull the whole file into memory. Just know that is what you're doing.\r\n\r\nLet's say our CSV file names are a little different than our class properties and we don't want to\r\nmake our properties match.\r\n\r\n```\r\nid,name\r\n1,one\r\n2,two\r\n```\r\n\r\nIn this case, the names are lower case. We want our property names to be Pascal Case, so we can\r\njust change how our properties match against the header names.\r\n\r\n```cs\r\nvar config = new CsvConfiguration(CultureInfo.InvariantCulture)\r\n{\r\n\tPrepareHeaderForMatch = args => args.Header.ToLower(),\r\n};\r\nusing (var reader = new StreamReader(\"path\\\\to\\\\file.csv\"))\r\nusing (var csv = new CsvReader(reader, config))\r\n{\r\n\tvar records = csv.GetRecords();\r\n}\r\n```\r\n\r\nUsing the configuration `PrepareHeaderForMatch`, we're able to change how the header matching\r\nis done against the property name. Both the header and the property name are ran through the\r\n`PrepareHeaderForMatch` function. When the reader needs to find the property to set for the\r\nheader, they will now match. You can use this function to do other things such as remove\r\nwhitespace or other characters.\r\n\r\nLet's say out CSV file doesn't have a header at all.\r\n\r\n```\r\n1,one\r\n2,two\r\n```\r\n\r\nFirst we need to tell the reader that there is no header record, using configuration.\r\n\r\n```cs\r\nvar config = new CsvConfiguration(CultureInfo.InvariantCulture)\r\n{\r\n\tHasHeaderRecord = false,\r\n};\r\nusing (var reader = new StreamReader(\"path\\\\to\\\\file.csv\"))\r\nusing (var csv = new CsvReader(reader, config))\r\n{\r\n\tvar records = csv.GetRecords();\r\n}\r\n```\r\n\r\nCsvReader will use the position of the properties in the class as the index position. There is an\r\nissue with this though. [You can't rely on the ordering of class members in .NET](https://blogs.msdn.microsoft.com/haibo_luo/2006/07/10/member-order-returned-by-getfields-getmethods/).\r\nWe can solve this by mapping the property to a position in the CSV file.\r\n\r\nOne way to do this is with attribute mapping.\r\n\r\n```cs\r\npublic class Foo\r\n{\r\n\t[Index(0)]\r\n\tpublic int Id { get; set; }\r\n\r\n\t[Index(1)]\r\n\tpublic string Name { get; set; }\r\n}\r\n```\r\n\r\nThe `IndexAttribute` allows you to specify which position the CSV field is that you want to use\r\nfor the property.\r\n\r\nYou can also map by name. Let's use our lower case header example from before and see how we can\r\nuse attributes instead of changing the header matching.\r\n\r\n```cs\r\npublic class Foo\r\n{\r\n\t[Name(\"id\")]\r\n\tpublic int Id { get; set; }\r\n\r\n\t[Name(\"name\")]\r\n\tpublic string Name { get; set; }\r\n}\r\n```\r\n\r\n[There are many other attributes you can use also.](/api/CsvHelper.Configuration.Attributes)\r\n\r\nWhat if we don't have control over the class we want to map to so we can't add attributes to it?\r\nIn this case, we can use a fluent `ClassMap` to do the mapping.\r\n\r\n```cs\r\npublic class FooMap : ClassMap\r\n{\r\n\tpublic FooMap()\r\n\t{\r\n\t\tMap(m => m.Id).Name(\"id\");\r\n\t\tMap(m => m.Name).Name(\"name\");\r\n\t}\r\n}\r\n```\r\n\r\nTo use the mapping, we need to register it in the context.\r\n\r\n```cs\r\nusing (var reader = new StreamReader(\"path\\\\to\\\\file.csv\"))\r\nusing (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))\r\n{\r\n\tcsv.Context.RegisterClassMap();\r\n\tvar records = csv.GetRecords();\r\n}\r\n```\r\n\r\nCreating a class map is the recommended way of mapping files in CsvHelper because it's a\r\nlot more powerful.\r\n\r\nYou can also read rows by hand.\r\n\r\n```cs\r\nusing (var reader = new StreamReader(\"path\\\\to\\file.csv\"))\r\nusing (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))\r\n{\r\n\tcsv.Read();\r\n\tcsv.ReadHeader();\r\n\twhile (csv.Read())\r\n\t{\r\n\t\tvar record = csv.GetRecord();\r\n\t\t// Do something with the record.\r\n\t}\r\n}\r\n```\r\n\r\n`Read` will advance row. `ReadHeader` will read the row into CsvHelper as the header values.\r\nSeparating `Read` and `ReadHeader` allows you to do other things with the header row before\r\nmoving onto the next row. `GetRecord` also does not advance the reader to allow you to do\r\nother things with the row you might need to do. You may need to `GetField` for a single field\r\nor maybe call `GetRecord` multiple times to fill more than one object.\r\n\r\n\r\n## Writing a CSV File\r\n\r\nNow let's look at how we can write CSV files. It's basically the same thing, but in reverse order.\r\n\r\nLet's use the same class definition as before.\r\n\r\n```cs\r\npublic class Foo\r\n{\r\n\tpublic int Id { get; set; }\r\n\tpublic string Name { get; set; }\r\n}\r\n```\r\n\r\nAnd we have a set of records like this.\r\n\r\n```cs\r\nvar records = new List\r\n{\r\n\tnew Foo { Id = 1, Name = \"one\" },\r\n\tnew Foo { Id = 2, Name = \"two\" },\r\n};\r\n```\r\n\r\nWe can write the records to a file without any configuration.\r\n\r\n```cs\r\nusing (var writer = new StreamWriter(\"path\\\\to\\\\file.csv\"))\r\nusing (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))\r\n{\r\n\tcsv.WriteRecords(records);\r\n}\r\n```\r\n\r\nThe `WriteRecords` method will write all the records to the file. After you are done writing,\r\nyou should call `writer.Flush()` to ensure that all the data in the writer's internal buffer\r\nhas been flushed to the file. Once a `using` block has exited, the writer is automatically\r\nflushed, so we don't have to explicitly do it here. It's recommended to always wrap any\r\n`IDisposable` object with `using` blocks. The object will dispose of itself (and in our case\r\nflush too) as soon as possible after the `using` block has exited.\r\n\r\nRemember how we can't rely on property order in .NET? If we are writing a class that has a header,\r\nit doesn't matter, as long as we are reading using the headers later. If we want to position\r\nthe headers in the CSV file, we need to specify an index to guarantee it's order. It's\r\nrecommended to always set an index when writing.\r\n\r\n```cs\r\npublic class FooMap : ClassMap\r\n{\r\n\tpublic FooMap()\r\n\t{\r\n\t\tMap(m => m.Id).Index(0).Name(\"id\");\r\n\t\tMap(m => m.Name).Index(1).Name(\"name\");\r\n\t}\r\n}\r\n```\r\n\r\nYou can also write rows by hand.\r\n\r\n```cs\r\nusing (var writer = new StreamWriter(\"path\\\\to\\\\file.csv\"))\r\nusing (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))\r\n{\r\n\tcsv.WriteHeader();\r\n\tcsv.NextRecord();\r\n\tforeach (var record in records)\r\n\t{\r\n\t\tcsv.WriteRecord(record);\r\n\t\tcsv.NextRecord();\r\n\t}\r\n}\r\n```\r\n\r\n`WriteHeader` will not advance you to the next row. Separating `NextRecord` from `WriteHeader`\r\nallows you to write more things in the header if you need to. `WriteRecord` also will not\r\nadvance you to the next row to give you the ability to write multiple objects or use\r\n`WriteField` to write individual fields.\r\n\r\n
\r\n","toc":{"title":"Getting Started","path":"getting-started","children":[{"title":"Installation","path":"getting-started#installation"},{"title":"CultureInfo","path":"getting-started#cultureinfo"},{"title":"Newlines","path":"getting-started#newlines"},{"title":"Reading a CSV File","path":"getting-started#reading-a-csv-file"},{"title":"Writing a CSV File","path":"getting-started#writing-a-csv-file"}]}},"path":"getting-started"}