Обработка записей в CSV-файле с помощью CSV Helper - PullRequest
0 голосов
/ 19 марта 2020

В настоящее время я использую помощник CSV для чтения содержимого файла CSV и вывода его на консоль. Я установил пакет Nuget csvHelper. Однако, когда я запускаю код, я получаю следующую ошибку:

CsvHelper.TypeConversion.TypeConverterException: 'Преобразование не может быть выполнено. Текст: '' MemberType: TypeConverter: 'CsvHelper.TypeConversion.Int32Converter' '

Я понимаю, что это связано с тем, что заполнение поля в CSV пусто. В настоящее время я хотел бы иметь возможность проверить поле и установить его в 0. Как я могу сделать это с CSVhelper.

Мой код для чтения CSV:

class ReaderCsv
    {
        private string _cvsfilepath;

        public ReaderCsv(string csvfilepath)
        {
            this._cvsfilepath = csvfilepath;
        }

        public List <Country>  ReadAllCountries()
        {
            var countries = new List<Country>();
            using (var sr = new StreamReader(_cvsfilepath))
            using (var csv = new CsvReader(sr, System.Globalization.CultureInfo.InvariantCulture))
            {


                csv.Configuration.Delimiter = ",";
                csv.Read();
                csv.ReadHeader();

                while (csv.Read()) 
                {
                    var country= new Country();

                    { 
                        country.CountryName = csv.GetField("CountryName");
                        country.CountryCode = csv.GetField("CountryCode");
                        country.Continent = csv.GetField("CountryCode");
                        country.Population = csv.GetField<int>("Population");


                    }
                    countries.Add(country);

                }
            }return countries;


        }

    }
}

мое отображение класс


public class CountryMap  : ClassMap<Country>
    {
        public CountryMap()
        {

            Map(m => m.CountryName);
            Map(m => m.CountryCode);
            Map(m => m.Continent);
            Map(m => m.Population);

        }


    }

Ответы [ 2 ]

0 голосов
/ 19 марта 2020

Вы можете использовать ClassMap, чтобы задать значение по умолчанию для Population

public class Program
{
    public static void Main(string[] args)
    {
        using (MemoryStream stream = new MemoryStream())
        using (StreamWriter writer = new StreamWriter(stream))
        using (StreamReader reader = new StreamReader(stream))
        using (CsvReader csv = new CsvReader(reader, CultureInfo.InvariantCulture))
        {
            writer.WriteLine("CountryName,CountryCode,Continent,Population");
            writer.WriteLine("TestName1,TestCode1,TestContinent1,");
            writer.WriteLine("TestName2,TestCode2,TestContinent2,2");
            writer.Flush();
            stream.Position = 0;

            csv.Configuration.RegisterClassMap<CountryMap>();

            var countries = csv.GetRecords<Country>().ToList();
        }

        Console.ReadKey();
    }
}

public class CountryMap : ClassMap<Country>
{
    public CountryMap()
    {
        Map(m => m.CountryName);
        Map(m => m.CountryCode);
        Map(m => m.Continent);
        Map(m => m.Population).Default(0);
    }
}

public class Country
{
    public string CountryName { get; set; }
    public string CountryCode { get; set; }
    public string Continent { get; set; }
    public int Population { get; set; }
}
0 голосов
/ 19 марта 2020

CSV Helper предоставляет перегрузки метода GetField, в который можно передать пользовательский преобразователь типов.

https://joshclose.github.io/CsvHelper/api/CsvHelper/CsvReader/

Следовательно; и не только для Int32, но и для любого типа, здесь есть реализация, использующая пользовательский преобразователь типа generi c, который возвращает значение по умолчанию для типа в случае сбоя преобразования.

Это не означает, что вы должны проглотить или игнорировать исключение. Этот преобразователь также выдаст вам ошибку преобразования и ошибочное значение, чтобы вы могли обработать эти недопустимые данные.

Я также добавил переменную lineNumber, чтобы отслеживать, на какой строке находятся недопустимые данные.

Я надеюсь, что это поможет.

public class Defaulter<T> : CsvHelper.TypeConversion.ITypeConverter
{
    Exception conversionError;
    string offendingValue;

    public Exception GetLastError()
    {
        return conversionError;
    }

    public string GetOffendingValue()
    {
        return offendingValue;
    }

    object CsvHelper.TypeConversion.ITypeConverter.ConvertFromString(string text, IReaderRow row, CsvHelper.Configuration.MemberMapData memberMapData)
    {
        conversionError = null;
        offendingValue = null;
        try
        {
            return (T)Convert.ChangeType(text, typeof(T));
        }
        catch (Exception localConversionError)
        {
            conversionError = localConversionError;
        }
        return default(T);
    }

    string CsvHelper.TypeConversion.ITypeConverter.ConvertToString(object value, IWriterRow row, CsvHelper.Configuration.MemberMapData memberMapData)
    {
        return Convert.ToString(value);
    }
}

А вот модифицированная версия вашего кода для отслеживания номера строки и обработки ошибки, если вы хотите:

public class ReaderCsv
{
    private string _cvsfilepath;

    public ReaderCsv(string csvfilepath)
    {
        this._cvsfilepath = csvfilepath;
    }

    public List<Country> ReadAllCountries()
    {
        var countries = new List<Country>();
        using (var sr = new StreamReader(_cvsfilepath))
        using (var csv = new CsvReader(sr, System.Globalization.CultureInfo.InvariantCulture))
        {
            csv.Configuration.Delimiter = ",";
            csv.Read();
            csv.ReadHeader();

            Defaulter<int> customInt32Converter = new Defaulter<int>();

            int lineNumber = 0;

            while (csv.Read())
            {
                lineNumber++;
                var country = new Country();
                {
                    country.CountryName = csv.GetField("CountryName");
                    country.CountryCode = csv.GetField("CountryCode");
                    country.Continent = csv.GetField("CountryCode");
                    country.Population = csv.GetField<int>("Population", customInt32Converter);

                    if (customInt32Converter.GetLastError() != null)
                    {
                        // The last conversion has failed.
                        // Handle it here.
                        string errorMessage = "The conversion of Population field on line " + lineNumber + " has failed. The Population value was: [" + customInt32Converter.GetOffendingValue() + "]";

                    }
                }
                countries.Add(country);

            }
        }
        return countries;
    }
}

С уважением.

...