Táto stránka pre svoju správnu funkčnosť vyžaduje súbory cookies. Slúžia na authentifikáciu návštevníka, analýzu návštevnosti a reklamnú personalizáciu.
logo
Prihlásenie / Registrácia
mobile

Zavrieť
 

CSVAdapter - Jednoduchá práca s CSV súbormi v .NET

Dnešný článok bude tak trochu netradičný. Nebudeme sa venovať nejakej technológii alebo nejakému mini projektu, ale predstavíme si knižnicu CSVAdapter z našej dielne.
V dnešnom netradičnom článku si predstavíme knižnicu CSVAdapter, ktorá vznikla s cieľom zjednodušiť prácu s CSV súbormi. Knižnica je prístupná na nasledujúcej adrese > link <

CSV súbory

Na úvod by sa asi patrilo napísať niečo aj o samotných CSV súboroch. CSV súbor je v podstate textový súbor, ktorý sa používa na prenos tabuľkových informácii medzi rôznymi aplikáciami / riešeniami.

Naneštastie formát CSV nemá jednotný formát, ktorý by každý rešpektoval. Používajú sa rozličné formáty textového zápisu hodnôt dátumu, čísel s desatinnou čiarkou, dokonca aj oddeľovača hodnôt. Aj keď názov formátu hovorí o "hodnotách oddelených čiarkou" (Comma-Separated Values), nie je to pravidlom. Ako oddeľovače sa okrem čiarky ,, používajú aj bodkočiarka ; alebo dokonca aj tabulátor.

V princípe však platí nasledovné:
- Jednotlivé riadky tabuľky (prípadne hlavička) sú skutočne oddelené "novým riadkom" (CRLF, LF, CR podľa platformy)
- Bunky v riadku sú oddelené oddelovačom
- Hodnoty v bunkách môžu (ale nemusia) byť uzavreté v úvodzovkách ", v prípade ak samotná hodnota obsahuje úvodzovky, je ich nutné zdvojiť a hodnotu uzavrieť do úvodzoviek. ("Toto je ""parádna"" hodnota").
- Ak hodnota v bunke obsahuje znak, ktorý je zároveň aj oddeľovač je nutné hodnoty uzavrieť do úvodzoviek.

Knižnica CSVAdapter

Ako už názov napovedá, tak knižnica CSVAdapter slúži ako adaptér medzi CSV a Vašou aplikáciou. Postará sa o načítanie / uloženie dát s/do CSV súboru, ktoré Vám aicky ponúkne ako .NETovú DataTable. Ako zdroj dát je možné použiť CSV súbor ale aj priamo textovú premennú obsahujúcu dáta. Zároveň je možné dáta načítať s aickou konverziou na požadované typy hodnôt, alebo ich načítať bez konverzie (všetky stĺpce v tabuľke budú typu String). Jednotlivé možnosti si teraz ukážeme na príkladoch.

Vytvorenie a nastavenie adaptéra

Do projektu pridáme referenciu na knižnicu CSVAdapter.dll, ktorú sme si pred tým stiahli zo stránky MST Bytes (> link <).

Následne si vytvoríme objekt Adapter typu CSVTableAdapter (namespace MSTBytes.Tools.CSVAdapter), v ktorom si nastavíme potrebné náležitosti:

Zdrojový kód:
using System;
using System.Data;
using System.Globalization;
using MSTBytes.Tools.CSVAdapter;

...

    CSVTableAdapter Adapter = new CSVTableAdapter(1);
    Adapter.Delimiter = ","; //Oddelovac hodnot
    Adapter.HeaderRows = 1; //Pocet riadkov, ktore su hlavickou (je zadany uz v konstruktore)

    //Nastavenie pre potreby konverzie hodnot
    Adapter.DateFormat = "yyyyMMdd"; //Format datumu
    Adapter.NumberFormat = new CultureInfo("en-US").NumberFormat; //Format cisel
    Adapter.AllowDBNull = false; //Nepovolit pouzivanie DBNull pri prazdnych bunkach (namiesto neho pouzit "Empty" hodnoty nizsie)

    //Nepovinne - Predvolene hodnoty pre prazdne bunky (ak je AllowDBNull true)
    Adapter.EmptyDateTimeValue = DateTime.MinValue;
    Adapter.EmptyStringValue = "";
    Adapter.EmptyDoubleValue = 0.0;
    Adapter.EmptyIntValue = 0;
...

Konštruktor má nepovinný parameter HeaderRows, ktorý hovorí o počte riadkov v súbore, ktoré majú byť považované za hlavičkové. Zvyčajne je hlavička v jednom riadku, no existujú aj výnimky (napríklad ak druhý riadok slúži ako krátky popis stĺpca, alebo ako cudzojazyčný názov stĺpca).

Ďalej sme si nastavili oddeľovač vo vlastnosti Delimiter a počet hlavičkových riadkov v HeaderRows (čo v tomto prípade nie je potrebné, keďže sme tak už spravili v hlavičke. Uvádzam len pre úplnosť).

Ak budeme používať aickú konverziu hodnôt, je potrebné nastaviť vlastnosti DateFormat a NumberFormat, kde uvedieme formáty, v ktorých by zdrojový / cieľový CSV mal byť uložený. Vlastnosť AllowDBNull riadi spôsob, akým sa parser vysporiada s prázdnymi údajmi v súbore. Ak je nastavená na true, interpretuje prázdnu hodnotu ako DBNull, ak je false, tak siahne po "prázdnej hodnote" z nastavení. Samotné "prázdne hodnoty" pre jednotlivé typy hodnôt, môžeme zadefinovať cez vlastnosti EmptyDateTimeValue, EmptyStringValue, EmptyDoubleValue a EmptyIntValue.

Uloženie dát do súboru

Dáta, ktoré máme obsiahnuté v tabuľke (DataTable), vieme jednoducho uložiť do CSV súboru cez metódu ToFile:

Zdrojový kód:
...
    DataTable Data = new DataTable();
    Data.Columns.Add("Item", typeof(string));
    Data.Columns.Add("Quantity", typeof(double));
    Data.Columns.Add("Duedate", typeof(DateTime));
    Data.Columns.Add("Price", typeof(double));

    Data.Rows.Add("I001", 23, new DateTime(2021, 12, 12), 35.1);
    Data.Rows.Add("I002", 22, new DateTime(2021, 12, 31), 1.5);

    CSVTableAdapter Adapter = new CSVTableAdapter(1);
    Adapter.Delimiter = ",";
    Adapter.DateFormat = "yyyyMMdd";
    Adapter.ToFile(Data, "test.csv");
...

V prípade, ak sú v tabuľke hodnoty typu Double alebo DateTime, budú aicky uložené vo formáte, ktorý je v adaptéry nastavený.

Načítanie dát zo súboru s aickou konverziou

Tento spôsob načítania dát použijeme v prípade, ak je nám štruktúra známa a vieme ju zadefinovať. Vytvoríme si prázdnu tabuľku s požadovanou štruktúrou a necháme adaptér, aby ju naplnil zo zadaného súboru. Na tento účel použijeme metódu FromFile.

Zdrojový kód:
...

    /*
    * Súbor by mal obsahovať:
    * Item,Quantity,DueDate,Price
    * I001,23,20211212,35.1
    * I002,22,20211231,1.5
    */

    DataTable Data = new DataTable();
    Data.Columns.Add("Item", typeof(string));
    Data.Columns.Add("Quantity", typeof(double));
    Data.Columns.Add("Duedate", typeof(DateTime));
    Data.Columns.Add("Price", typeof(double));

    CSVTableAdapter Adapter = new CSVTableAdapter(1);
    Adapter.Delimiter = ",";
    Adapter.DateFormat = "yyyyMMdd";
    Adapter.FromFile(ref Data, "test.csv");

...

Načítanie dát zo súboru s bez konverzie

V prípade, ak chceme len načítať obsah CSV súboru, bez toho, aby boli hodnoty nejako upravované, môžeme zavolať metódu FromFileRaw, ktorá načíta "surové" (Raw) dáta do tabuľky. V tomto prípade, štruktúru tabuľky vopred nedefinujeme, adaptér ju aicky vytvorí podľa hodnôt v hlavičke a všetky stĺpce budú typu String.

Zdrojový kód:
...

    /*
    * Súbor by mal obsahovať:
    * Item,Quantity,DueDate,Price
    * I001,23,20211212,35.1
    * I002,22,20211231,1.5
    */

    CSVTableAdapter Adapter = new CSVTableAdapter(1);
    Adapter.Delimiter = ",";
    DataTable Data = Adapter.FromFileRaw("test.csv");

...

Načítanie / uloženie dát z / do premennej

Alternatívou k práci so súbormi je možnosť pracovať s dátami v premennej typu String. Práca s nimi je rovnaká ako v predchádzajúcich príkladoch, avšak sa používajú metódy, ktoré nemajú v názve File ale String. Takže namiesto FromFile použijeme FromString.

Zdrojový kód:
...

    string CSVData = "Item,Quantity,DueDate,Price" + Environment.NewLine
            + "I001,23,20211212,35.1" + Environment.NewLine
            + "I002,22,20211231,1.5";

    DataTable Data = new DataTable();
    Data.Columns.Add("Item", typeof(string));
    Data.Columns.Add("Quantity", typeof(double));
    Data.Columns.Add("Duedate", typeof(DateTime));
    Data.Columns.Add("Price", typeof(double));

    CSVTableAdapter Adapter = new CSVTableAdapter(1);
    Adapter.Delimiter = ",";
    Adapter.DateFormat = "yyyyMMdd";
    Adapter.AllowDBNull = false;
    Adapter.FromString(ref Data, CSVData);

...

Vlastné parsovanie hodnôt

Ak by súbor, ktorý chceme načítať, obsahoval dáta v neštandardnom formáte, ktorý nevieme zadefinovať cez štandardné prostriedky, je možné pre tieto hodnoty vytvoriť vlastný parser, ktorý sa v prípade potreby použije počas parsovania vstupného súboru / reťazca. Pre tento účel ma adaptér event OnValueParsing, ktorý je vyvolaný pred každým parsovaním hodnoty. V prípade, ak obsluha eventu nechá premennú ParsedValue nezmenenú, prebehne štandardné parsovanie. V opačnom prípade sa táto hodnota použije ako výsledok parsovania.

Zdrojový kód:
private static void CustomParsing_Example()
{
    string CSVData = "Item,Quantity,DueDate,Price" + Environment.NewLine
        + "I001,23,1,35.1" + Environment.NewLine
        + "I002,22,2,1.5";

    DataTable Data = new DataTable();
    Data.Columns.Add("Item", typeof(string));
    Data.Columns.Add("Quantity", typeof(double));
    Data.Columns.Add("Duedate", typeof(DateTime));
    Data.Columns.Add("Price", typeof(double));

    CSVTableAdapter Adapter = new CSVTableAdapter(1);
    Adapter.Delimiter = ",";
    Adapter.DateFormat = "yyyyMMdd";
    Adapter.AllowDBNull = false;
    Adapter.OnValueParsing += Adapter_OnValueParsing;
    Adapter.FromString(ref Data, CSVData);
}

private static void Adapter_OnValueParsing(string Value, int RowIndex, int ColumnIndex, DataTable Table, ref object ParsedValue)
{
    //Vlastne parsovanie stlpca Duedate
    if (ColumnIndex == 2)
    {
        DateTime ActualDate = DateTime.Now.Date;
        int Days;

        if (String.IsNullOrEmpty(Value))
        {
            ParsedValue = ActualDate;
        }
        else if (Int32.TryParse(Value, out Days))
        {
            ParsedValue = ActualDate.AddDays(Days);
        }
        else
        {
            ParsedValue = DBNull.Value;
        }
    }
}

V príklade sme si ukázali, ako parsovať dátumovú hodnotu, ktorá je zapísaná ako počet dní od dátumu načítania dát.

Vlastné formátovanie hodnôt

Rovnaký prípad neštandardného formátovania môže nastať aj pri zápise dát do súboru / reťazca. Na uplatnenie vlastného formátu hodnoty pri zápise je možné použiť event OnValueFormating, ktorý funguje obdobne ako OnValueParsing.

Zdrojový kód:
private static void CustomFormating_Example()
{
    DataTable Data = new DataTable();
    Data.Columns.Add("Item", typeof(string));
    Data.Columns.Add("Quantity", typeof(double));
    Data.Columns.Add("Duedate", typeof(DateTime));
    Data.Columns.Add("Price", typeof(double));

    Data.Rows.Add("I001", 23, new DateTime(2021, 12, 12), 35.1);
    Data.Rows.Add("I002", 22, new DateTime(2021, 12, 31), 1.5);

    CSVTableAdapter Adapter = new CSVTableAdapter(1);
    Adapter.Delimiter = ",";
    Adapter.DateFormat = "yyyyMMdd";
    Adapter.OnValueFormating += Adapter_OnValueFormating;
    string Result = Adapter.ToString(Data);
}

private static void Adapter_OnValueFormating(object Value, int RowIndex, int ColumnIndex, DataTable Table, ref string FormatedValue)
{
    //Vlastne formatovanie stlpca Duedate
    if (ColumnIndex == 2)
    {
        DateTime dtValue = (DateTime)Value;
        DateTime ActualDate = DateTime.Now.Date;

        TimeSpan Diff = dtValue - ActualDate;
        FormatedValue = Convert.ToString(Convert.ToInt32(Math.Round(Diff.TotalDays, 0)));
    }
}

Záverom

To je pre dnešok všetko. Ukázali sme si princíp práce s knižnicou CSVAdapter a dúfam, že boli príklady zrozumiteľné a ľahko pochopiteľné. Pri písaní tohto článku bola použitá knižnica vo verzii 0.9.0.5, kde úvodná 0 naznačuje, že je knižnica stále vo fáze vývoja a uvítame všetky vaše podnety na zlepšenie aj prípadne hlásenia chýb. Urobiť tak môžete cez kontaktný formulár na stránke MST Bytes > link <

Codeblog
Diskusia

Žiadne príspevky v diskusii.

Nový príspevok

Na prispievanie do diskusie musíte byť prihlásený.