I know how to do this via streamreader and read to the end of line, but was curious if there was a fancier way of going it (for the sake of learing).
filename: blah.csv
File layout is simple:
"Some234234 ", 234
"blahblha234234 ", 2322
I want to load this into a dictionary (the second part should be a int, but I will parse later in case of errors).
Can you do this via linq somehow?
7 Answers 7
You should use the TextFieldParser class in Microsoft.VisualBasic.dll. (There's nothing wrong with using it in C#.
Remember that CSV is a much more complicated file format than you think; both quotes and newlines can be escaped.
-
Very true, and I have used it many times this way for complex csv's or csv's with unpredictable contents. But this is only necessary if you expect a complex file. In some cases it's a very simple file, for example all integer values.richard– richard2013年12月29日 01:36:20 +00:00Commented Dec 29, 2013 at 1:36
CSV can be a lot more complicated than it appears at first. Here is an excellent library for reading CSV files.
-
2I agree with this and with SLaks's reply. The most effective way to solve any problem is to use a solution that already exists. CSV seems to be one of those features that's just simple enough for people to re-invent on a whim, but still complex enough for most of them to make a mess out of.Aaronaught– Aaronaught2009年12月10日 21:43:04 +00:00Commented Dec 10, 2009 at 21:43
Untested, but:
static IEnumerable<string> ReadLines(string path) {
using (var file = File.OpenText(path)) {
string line;
while ((line = file.ReadLine()) != null) {
yield return line;
}
}
}
var data = (from line in ReadLines(path)
select line.Split(','))
.ToDictionary(
arr => arr[0].Trim('"', ' '),
arr => int.Parse(arr[1].Trim()));
-
2This will not handle escaped CSV files. Even if the CSV files aren't escaped right now, they might be in the future.SLaks– SLaks2009年12月10日 20:55:33 +00:00Commented Dec 10, 2009 at 20:55
foreach (string s in File.ReadAllLines(filename)) {
var vals = s.Split(',')
dictionary[vals[0]] = vals[1];
}
No LINQ but this is simple really. Doesn't handle embedded ',''s in the first value though.
-
This will not handle escaped CSV files. Even if the CSV files aren't escaped right now, they might be in the future.SLaks– SLaks2009年12月10日 20:56:03 +00:00Commented Dec 10, 2009 at 20:56
-
He obviously doesn't care about things like this as he put it "for the sake of learing." CSV isn't even a standardized format, his CSV might not allow escaping.Ron Warholic– Ron Warholic2009年12月10日 20:59:23 +00:00Commented Dec 10, 2009 at 20:59
string[] file = File.ReadAllLines(@"C:\temp\dictionary.txt");
Dictionary<string, string> b = (from p in file
let x = p.Split(',')
select x).ToDictionary(a => a[0], a => a[1]);
-
This will not handle escaped CSV files. Even if the CSV files aren't escaped right now, they might be in the future.SLaks– SLaks2009年12月10日 20:56:33 +00:00Commented Dec 10, 2009 at 20:56
You could use File.ReadAllLines(), Select() and ToDictionary() to do this:
var d = File.ReadAllLines(file).Select( l => {
var split = l.Split(',');
return new { Key = split[0], Value = split[1] };
} ).ToDictionary( p => p.Key, p => p.Value );
But there are obvious problems here with respect to error handling and robustness, and as you add those, it gets worse and worse. I don't feel there's a particular good reason prefer LINQ or its extension methods here, as it isn't buying you much. The straightforward ways, posted already, are much cleaner.
EDIT: Sid's answer, for example, contains essentially the same code, but written in a much, much cleaner form by avoiding all this "fancy" junk.
This might be overkill in your simple scenario, but for CSV to strongly typed collection conversion, I usually use FileHelpers.
It's a great tool to have in the tool box.
-
How can i use filehelpers to load CSV into the pregenereterd OR classes that can be used in LINQ2SQL instead of creating new class and assigning each damn field to it? I have a old school table with 300+ columns.. yayPiotr Kula– Piotr Kula2012年10月10日 10:43:48 +00:00Commented Oct 10, 2012 at 10:43
-
I don't know your "pregenerated OR classes", but if minimizing code and violate SRP is okay, I guess you could use the same types and add the appropriate FileHelpers attributes. Personally, I'd separate the concerns, and map from the FileHelper types to the L2S types with AutoMapper.Martin R-L– Martin R-L2012年10月10日 11:41:57 +00:00Commented Oct 10, 2012 at 11:41