2016-07-21 3 views
0

Ich versuche, zwei Arten von Datensätzen aus einer CSV mit der folgenden Struktur-Datei zu lesen:CsvHelper - Lesen Sie verschiedene Datensatztypen in gleichen CSV

PlaceName,Longitude,Latitude,Elevation 
NameString,123.456,56.78,40 

Date,Count 
1/1/2012,1 
2/1/2012,3 
3/1/2012,10 
4/2/2012,6 

ich diese Frage wissen, wurde in

vorher abgedeckt

aber Wenn ich meine Implementierung ausführen, erhält es eine CsvMissingFieldException, die besagt, dass Fields 'Date' do not exist in the CSV file. Ich habe zwei Definition und Karten Klassen, eine für den Standort und die andere für den Grafen, die da sind:

public class LocationDefinition 
{ 
    public string PlaceName { get; set; } 
    public double Longitude { get; set; } 
    public double Latitude { get; set; } 
    public double Elevation { get; set; } 
} 

public sealed class LocationMap : CsvClassMap<LocationDefinition> 
{ 
    public LocationMap() 
    { 
     Map(m => m.PlaceName).Name("PlaceName"); 
     Map(m => m.Longitude).Name("Longitude"); 
     Map(m => m.Latitude).Name("Latitude"); 
     Map(m => m.Elevation).Name("Elevation"); 
    }    
}  

public class CountDefinition 
{ 
    public DateTime Date { get; set; } 
    public int Count { get; set; } 
} 

public sealed class CountMap : CsvClassMap<CountDefinition> 
{ 
    public CountMap() 
    { 
     Map(m => m.Date).Name("Date"); 
     Map(m => m.Count).Name("Count"); 
    } 
} 

Der Code, den ich zum Lesen der CSV-Datei haben, ist:

LocationDefinition Location; 
var Counts = new List<CountDefinition>(); 

using (TextReader fileReader = File.OpenText(@"Path\To\CsvFile")) 
using (var csvReader = new CsvReader(fileReader)) 
{ 
    csvReader.Configuration.RegisterClassMap<LocationMap>(); 
    csvReader.Configuration.RegisterClassMap<CountMap>(); 

    // Only reads a single line of Location data 
    csvReader.Read(); 
    LocationData = csvReader.GetRecord<LocationDefinition>(); 
    csvReader.Read(); // skip blank line 
    csvReader.Read(); // skip second header section 

    // Read count data records 
    while (csvReader.Read()) 
    { 
     var tempCount = csvReader.GetRecord<CountDefinition>(); 
     Counts.Add(tempCount); 
    } 
} 

Die Ausnahme wird auf die Linie geworfen. Von dem, was ich sagen kann, erwartet es immer noch einen Standortdatensatz, aber ich hätte gedacht, GetRecord<CountDefinition> würde den Datensatztyp angeben. Ich habe auch versucht, ClearRecordCache und die Registrierung der LocationMap vergeblich.

Wie sollte dieser Code geändert werden, damit er eine CSV-Datei dieser Struktur liest?

+1

Wiederholt sich die Struktur? Können Sie mehr als eine Struktur buchen? Seit 40 Jahren fils fils wie dies zu analysieren und kann leicht eine großartige Lösung geben. – jdweng

+0

Der Standortbereich tritt nur einmal auf und befindet sich vor dem Zählabschnitt (derzeit hat er nur einen Datensatz), der Zählabschnitt kann eine beliebige Anzahl von Datensätzen haben. Es könnte sich lohnen, den Code in die Lage zu versetzen, eine beliebige Anzahl von Standortdatensätzen zu verarbeiten. – Ayb4btu

+0

Ich würde die Datei in zwei teilen, wo die CRLF erscheint. Sobald der Ort def initialisiert ist, kann ich ihn nicht loslassen. – Plutonix

Antwort

0

bekam ich eine Antwort von Josh Schließen auf der issue tracker:

CsvReader not recognising different registered class maps

Hier ist seine Antwort auf diese Frage:

Da Sie Haben Sie keinen einzigen Header, müssen Sie die Header ignorieren und Indizes verwenden stattdessen. Dies bringt jedoch eine Idee auf. Ich könnte die ReadHeader-Methode Parse-Header für einen bestimmten Datensatztyp haben.

Hier ist ein Beispiel, das für Sie arbeiten sollte.

void Main() 
{ 
    LocationDefinition Location; 
    var Counts = new List<CountDefinition>(); 

    using (var stream = new MemoryStream()) 
    using (var reader = new StreamReader(stream)) 
    using (var writer = new StreamWriter(stream)) 
    using (var csvReader = new CsvReader(reader)) 
    { 
     writer.WriteLine("PlaceName,Longitude,Latitude,Elevation"); 
     writer.WriteLine("NameString,123.456,56.78,40"); 
     writer.WriteLine(); 
     writer.WriteLine("Date,Count"); 
     writer.WriteLine("1/1/2012,1"); 
     writer.WriteLine("2/1/2012,3"); 
     writer.WriteLine("3/1/2012,10"); 
     writer.WriteLine("4/2/2012,6"); 
     writer.Flush(); 
     stream.Position = 0; 

     csvReader.Configuration.HasHeaderRecord = false; 
     csvReader.Configuration.RegisterClassMap<LocationMap>(); 
     csvReader.Configuration.RegisterClassMap<CountMap>(); 

     csvReader.Read(); // get header 
     csvReader.Read(); // get first record 
     var locationData = csvReader.GetRecord<LocationDefinition>(); 

     csvReader.Read(); // skip blank line 
     csvReader.Read(); // skip second header section 

     // Read count data records 
     while (csvReader.Read()) 
     { 
      var tempCount = csvReader.GetRecord<CountDefinition>();   
      Counts.Add(tempCount); 
     } 
    } 
} 

public class LocationDefinition 
{ 
    public string PlaceName { get; set; } 
    public double Longitude { get; set; } 
    public double Latitude { get; set; } 
    public double Elevation { get; set; } 
} 

public sealed class LocationMap : CsvClassMap<LocationDefinition> 
{ 
    public LocationMap() 
    { 
     Map(m => m.PlaceName); 
     Map(m => m.Longitude); 
     Map(m => m.Latitude); 
     Map(m => m.Elevation); 
    } 
} 

public class CountDefinition 
{ 
    public DateTime Date { get; set; } 
    public int Count { get; set; } 
} 

public sealed class CountMap : CsvClassMap<CountDefinition> 
{ 
    public CountMap() 
    { 
     Map(m => m.Date); 
     Map(m => m.Count); 
    } 
} 
0

Versuchen Sie, diese

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.IO; 

namespace ConsoleApplication1 
{ 
    enum State 
    { 
     FIND_RECORD, 
     GET_LOCATION, 
     GET_DATES 
    } 
    class Program 
    { 
     const string FILENAME = @"c:\temp\test.txt"; 
     static void Main(string[] args) 
     { 
      StreamReader reader = new StreamReader(FILENAME); 
      State state = State.FIND_RECORD; 

      LocationDefinition location = null; 
      string inputLine = ""; 
      while ((inputLine = reader.ReadLine()) != null) 
      { 
       inputLine = inputLine.Trim(); 
       if (inputLine.Length == 0) 
       { 
        state = State.FIND_RECORD; 
       } 
       else 
       { 
        switch (state) 
        { 
         case State.FIND_RECORD : 
          if (inputLine.StartsWith("PlaceName")) 
          { 
           state = State.GET_LOCATION; 
          } 
          else 
          { 
           if (inputLine.StartsWith("Date")) 
           { 
            state = State.GET_DATES; 
           } 
          } 
          break; 
         case State.GET_DATES : 
          if (location.dates == null) location.dates = new CountDefinition(); 
          location.dates.dates.Add(new CountDefinition(inputLine)); 
          break; 
         case State.GET_LOCATION : 
          location = new LocationDefinition(inputLine); 
          break; 
        } 
       } 
      } 
     } 
    } 
    public class LocationDefinition 
    { 
     public static List<LocationDefinition> locations = new List<LocationDefinition>(); 
     public CountDefinition dates { get; set; } 
     public string PlaceName { get; set; } 
     public double Longitude { get; set; } 
     public double Latitude { get; set; } 
     public double Elevation { get; set; } 

     public LocationDefinition(string location) 
     { 
      string[] array = location.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); 
      PlaceName = array[0]; 
      Longitude = double.Parse(array[1]); 
      Latitude = double.Parse(array[2]); 
      Elevation = double.Parse(array[3]); 
      locations.Add(this); 
     } 
    } 



    public class CountDefinition 
    { 
     public List<CountDefinition> dates = new List<CountDefinition>(); 
     public DateTime Date { get; set; } 
     public int Count { get; set; } 

     public CountDefinition() { ;} 

     public CountDefinition(string count) 
     { 
      string[] array = count.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); 
      Date = DateTime.Parse(array[0]); 
      Count = int.Parse(array[1]); 
      dates.Add(this); 
     } 
    } 


} 
+0

Ich hatte auf eine Korrektur für meinen CsvHelper-Code gehofft, obwohl dies für jeden nützlich ist, der eine externe Bibliothek vermeiden möchte. – Ayb4btu

+0

Warum sollte jemand eine Drittanbieter-App verwenden, um einfach eine Textdatei zu lesen, wenn dies mit der String-Split-Funktion einfach möglich ist? – jdweng