Greetings fellow programmers, I need to ask you for a help.
I have this programm:
private void Import_CSV_Click(object sender, System.Windows.RoutedEventArgs e)
{
List<List<string>> x = new List<List<string>>();
try
{
List<string> row = new List<string>();
OpenFileDialog browseDialog = new OpenFileDialog();
browseDialog.Filter = "CSV Files (*.csv)|*.csv";
browseDialog.ShowDialog();
StreamReader sr = new StreamReader(browseDialog.FileName, Encoding.Default, true);
List<TOsoby> persons = new List<TOsoby>();
var file = sr.ReadToEnd();
var linesinthestream = file.Split(new char[] { '\n' });
for (int i = 0; i < linesinthestream.Count()-2; i )
{
persons.Add(new TOsoby());
}
sr = new StreamReader(browseDialog.FileName, Encoding.Default, true);
string firstline = Akro.Helpers.String.RemoveDiacritics(sr.ReadLine().ToLower());
string[] values = firstline.Split(';');
for (int i = 0; i < values.Length; i )
{
row.Add(values[i]);
}
x.Add(row);
while (!sr.EndOfStream)
{
row = new List<string>();
string lines = sr.ReadLine();
values = lines.Split(';');
for (int i = 0; i < values.Length; i )
{
row.Add(values[i]);
}
x.Add(row);
}
for (int i = 0; i < x[0].Count-2; i )
{
if (x[0][i] == "jmeno") //Tady je chyba J = 22. a count je 24 upakovaní neprojde.
{
for (int j = 0; j < x.Count-2; j )
{
persons[j].Jmeno = x[j][i].ToString();
}
}
else if (x[0][i] == "name")
{
for (int j = 0; j < x.Count - 2; j )
{
persons[j].Jmeno = x[j][i].ToString();
}
}
else if (x[0][i] == "firstname")
{
for (int j = 0; j < x.Count - 2; j )
{
persons[j].Jmeno = x[j][i].ToString();
}
}
else if (x[0][i] == "prijmeni")
{
for (int j = 0; j < x.Count - 2; j )
{
persons[j].Prijmeni = x[j][i].ToString();
}
}
else if (x[0][i] == "surname")
{
for (int j = 0; j < x.Count - 2; j )
{
persons[j].Prijmeni = x[j][i].ToString();
}
}
else if (x[0][i] == "lastname")
{
for (int j = 0; j < x.Count - 2; j )
{
persons[j].Prijmeni = x[j][i].ToString();
}
}
else if (x[0][i] == "familyname")
{
for (int j = 0; j < x.Count - 2; j )
{
persons[j].Prijmeni = x[j][i].ToString();
}
}
else if (x[0][i] == "titul")
{
for (int j = 0; j < x.Count - 2; j )
{
persons[j].Titul = x[j][i].ToString();
}
}
else if (x[0][i] == "title")
{
for (int j = 0; j < x.Count - 2; j )
{
persons[j].Titul = x[j][i].ToString();
}
}
else if (x[0][i] == "email")
{
for (int j = 0; j < x.Count - 2; j )
{
persons[j].Email = x[j][i].ToString();
}
}
else if (x[0][i] == "")
{
return;
}
for (int j = 0; j < x.Count - 2; j )
{
persons[j].OsobaID = 0;
}
}
if (persons == null) //Musím odstranit [0], protože tam je uložený první řádek a taky potřebujeme tam dát 23 řádků, takže nám tam 2 entry chybí (Marie a Michal), ale 22. řádek je uložen jako "", takže to musíme nějak opravit.
{
return;
}
else
{
persons.RemoveAt(0); //Tohle opravý ten první řádek
EntitiesModel em = DB.GetDB();
em.Add(persons); //23 a 24 tam vůbec nejsou (lidi z excelu)
em.SaveChanges();
Checker.CheckAfterEverySave();
}
}
catch (Exception er)
{
MessageBox.Show(er.Message);
}
}
My quest is to read the CSV entries and save them into the database, my problem is that last two entries of my CSV are not inside the persons, also on the last index it is empty:
Here is my CSV example I generated:
How should I fix it please?
CodePudding user response:
Have a look at this, I included comments where I did changes to your code.
var csvFile = "A;B;C\nA 1;B 1;C 1\nA 2;B 2;C 2\nA 3;B 3;C 3\nA 4;B 4;C 4\n";
List<List<string>> x = new List<List<string>>();
List<Foo> foos = new List<Foo>();
//use StringSplitOptions.RemoveEmptyEntries to remove potential empty line at the end
var linesinthestream = csvFile.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < linesinthestream.Length - 1; i ) //-1 instead of - 2
foos.Add(new Foo());
List<string> row = new List<string>();
string firstline = linesinthestream[0];
string[] values = firstline.Split(';');
for (int i = 0; i < values.Length; i )
row.Add(values[i]);
x.Add(row);
//use linesinthestream instead of again reading a stream start for loop at 1 and not 0 to skip the header
//you could remove the above code to read the header with this and start at 0, you don't really do anything different
for (int i = 1; i < linesinthestream.Length; i )
{
row = new List<string>();
string lines = linesinthestream[i];
values = lines.Split(';');
for (int j = 0; j < values.Length; j )
row.Add(values[j]);
x.Add(row);
}
//remove -2 to read all columns
for (int i = 0; i < x[0].Count; i )
{
if (x[0][i] == "A")
{
//remove -2, start loop at 1, fill foo[j-1]
for (int j = 1; j < x.Count; j )
foos[j-1].HeaderA = x[j][i].ToString();
}
else if (x[0][i] == "B")
{
//remove -2, start loop at 1, fill foo[j-1]
for (int j = 1; j < x.Count; j )
foos[j-1].HeaderB = x[j][i].ToString();
}
else if (x[0][i] == "C")
{
//remove -2, start loop at 1, fill foo[j-1]
for (int j = 1; j < x.Count; j )
foos[j-1].HeaderC = x[j][i].ToString();
}
}
//moved this loop outside of the previous loop, don't need to do it for every column
for (int j = 1; j < x.Count; j )
foos[j-1].Id = 0;
foreach(var foo in foos)
Console.WriteLine($"Id: {foo.Id} | HeaderA: {foo.HeaderA} | HeaderB: {foo.HeaderB} | HeaderC: {foo.HeaderC}");
Find a demo here:
https://dotnetfiddle.net/tj0azu
As was already pointed out you should consider usign a library eg. https://github.com/JoshClose/CsvHelper
and you can achieve the same result with this code:
using System;
using CsvHelper;
using CsvHelper.Configuration;
using System.Globalization;
using System.IO;
public class Program
{
public static void Main()
{
var csvFile = "A;B;C\nA 1;B 1;C 1\nA 2;B 2;C 2\nA 3;B 3;C 3\nA 4;B 4;C 4\n";
using (var reader = new StringReader(csvFile))
using (var csvReader = new CsvReader(reader, new CsvConfiguration(CultureInfo.InvariantCulture) { Delimiter = ";" }))
{
csvReader.Context.RegisterClassMap<FooMap>();
var foos = csvReader.GetRecords<Foo>();
foreach(var foo in foos)
Console.WriteLine($"Id: {foo.Id} | HeaderA: {foo.HeaderA} | HeaderB: {foo.HeaderB} | HeaderC: {foo.HeaderC}");
}
}
}
public class Foo
{
public int Id {get;set;}
public string HeaderA {get;set;}
public string HeaderB {get;set;}
public string HeaderC {get;set;}
}
public sealed class FooMap : ClassMap<Foo>
{
public FooMap()
{
AutoMap(CultureInfo.InvariantCulture);
Map(m => m.Id).Ignore();
Map(m => m.HeaderA).Name("A");
Map(m => m.HeaderB).Name("B");
Map(m => m.HeaderC).Name("C");
}
}
Find a demo here:
https://dotnetfiddle.net/1jaYNw
CodePudding user response:
I recommend using FileHelpers. There is a nuget package available. I have used this for parsing several CSV files with no issue.
Here is some example code that will read a CSV file through a Stream
and create a List<T>
of the class
that is provided:
using FileHelpers;
using System;
using System.Collections.Generic;
using System.IO;
public class DataFileConverter<T> : IDisposable where T : class
{
private readonly IFileHelperAsyncEngine<T> _engine;
private bool _disposed = false;
public DataFileConverter()
{
_engine = new FileHelperAsyncEngine<T>();
}
~DataFileConverter()
{
Dispose(false);
}
public bool RemoveHeaderRow
{
get => _engine.Options.IgnoreFirstLines == 1;
set => _engine.Options.IgnoreFirstLines = value ? 1 : 0;
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
if (_engine != null)
{
_engine.Close();
}
}
_disposed = true;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public List<T> ReadDataFile(Stream stream)
{
List<T> data = new List<T>();
using var streamReader = new StreamReader(stream);
using (_engine.BeginReadStream(streamReader))
{
foreach (T datum in _engine)
{
data.Add(datum);
}
}
return data;
}
}
using FileHelpers;
using System;
[DelimitedRecord(",")]
public class SomeClass
{
[FieldCaption("column1")]
public string SomeProperty1 { get; set; }
[FieldCaption("column2")]
[FieldConverter(ConverterKind.Date, "yyyy-MM-dd")]
public DateTime SomeProperty2 { get; set; }
}
public class SomeService
{
using DataFileConverter<SomeClass> converter = new DataFileConverter<SomeClass>
{
RemoveHeaderRow = true
};
List<SomeClass> data = converter.ReadDataFile(System.IO.File.OpenRead("path/to/file"));
// do whatever logic with data
}