2

As per in this FileHelpers 3.1 example, you can automatically detect a CSV file format using the FileHelpers.Detection.SmartFormatDetector class.

But the example goes no further. How do you use this information to dynamically parse a CSV file? It must have something to do with the DelimitedFileEngine but I cannot see how.

Update:

I figured out a possible way but had to resort to using reflection (which does not feel right). Is there another/better way? Maybe using System.Dynamic? Anyway, here is the code I have so far, it ain't pretty but it works:

        // follows on from smart detector example

        FileHelpers.Detection.RecordFormatInfo lDetectedFormat = formats[0];

        Type lDetectedClass = lDetectedFormat.ClassBuilderAsDelimited.CreateRecordClass();

        List<FieldInfo> lFieldInfoList = new List<FieldInfo>(lDetectedFormat.ClassBuilderAsDelimited.FieldCount);
        foreach (FileHelpers.Dynamic.DelimitedFieldBuilder lField in lDetectedFormat.ClassBuilderAsDelimited.Fields)
            lFieldInfoList.Add(lDetectedClass.GetField(lField.FieldName));

        FileHelperAsyncEngine lFileEngine = new FileHelperAsyncEngine(lDetectedClass);
        int lRecNo = 0;
        lFileEngine.BeginReadFile(cReadingsFile);
        try
        {
            while (true)
            {
                object lRec = lFileEngine.ReadNext();
                if (lRec == null)
                    break;

                Trace.WriteLine("Record " + lRecNo);
                lFieldInfoList.ForEach(f => Trace.WriteLine("   " + f.Name + " = " + f.GetValue(lRec)));

                lRecNo++;
            }
        }
        finally
        {
            lFileEngine.Close();
        }
VinceJS
  • 1,254
  • 3
  • 18
  • 38
  • Doesn't dynamic just mean it used reflection and late binding anyway? Reflection is always a performance hit so the only other method would be to use Linq Expressions – netniV Sep 10 '15 at 23:31

1 Answers1

0

As I use the SmartFormatDetector to determine the exact format of the incoming Delimited files you can use following appoach:

    private DelimitedClassBuilder GetFormat(string file)
    {
        var detector = new FileHelpers.Detection.SmartFormatDetector();
        var format = detector.DetectFileFormat(file);

        return format.First().ClassBuilderAsDelimited;
    }

    private List<T> ConvertFile2Objects<T>(string file, out DelimitedFileEngine engine)
    {
        var format = GetSeperator(file); // Get Here your FormatInfo
        engine = new DelimitedFileEngine(typeof(T)); //define your DelimitdFileEngine

        //set some Properties of the engine with what you need
        engine.ErrorMode = ErrorMode.SaveAndContinue; //optional
        engine.Options.Delimiter = format.Delimiter;
        engine.Options.IgnoreFirstLines = format.IgnoreFirstLines;
        engine.Options.IgnoreLastLines = format.IgnoreLastLines;
        //process
        var ret = engine.ReadFileAsList(file);
        this.errorCount = engine.ErrorManager.ErrorCount;
        var err = engine.ErrorManager.Errors;
        engine.ErrorManager.SaveErrors("errors.out");
        //return records do here what you need
        return ret.Cast<T>().ToList();
    }

This is an approach I use in a project, where I only know that I have to process Delimited files of multiple types.

Attention: I noticed that with the files I recieved the SmartFormatDetector has a problem with tab delimiter. Maybe this should be considered.

Disclaimer: This code is not perfected but in a usable state. Modification and/or refactoring is adviced.