Blog Dla Młodszych Programistów C#/.NET

Pliki CSV w C# - Najważniejsze Informacje

W dzisiejszym artykule stworzymy prostą aplikację w Windows Forms w języku C#, która będzie tworzyła oraz zapisywała dane do pliku z rozszerzeniem CSV, a także pokaże Ci jak odczytywać dane z takiego pliku i wyświetlać je w aplikacji. Opowiem także, czym jest format CSV i dlaczego często jest stosowany w programowaniu.



Czym są pliki CSV?

Pliki CSV w C# - Najważniejsze Informacje - 1

Plik o rozszerzeniu CSV jest to specjalny typ pliku, który przechowuje wartości rozdzielone przecinkami. Takie pliki można między innymi uruchamiać, a także edytować w programie Excel. Taki typ pliku jest często używany w programowaniu, ponieważ są to zwykłe, proste, lekkie pliki, gdzie oddzielamy od siebie jakieś dane, które później możemy łatwo przywrócić i zmapować na model. Możemy przechowywać w takim formacje różne dane. Często możemy dać opcję importowania danych użytkownikowi i właśnie w łatwy sposób możemy importować takie dane do formatu CSV. Ja pokaże Ci w tym artykule, jak obsłużyć to po stronie języka C#.



Zadanie do zrealizowania

Pliki CSV w C# - Najważniejsze Informacje - 2

Jako, że lubię uczyć poprzez praktykę, to stworzymy sobie teraz prostą aplikację w C#.

Mamy do stworzenia aplikację, która ma przechowywać listę mailową użytkownika. Czyli użytkownik zbiera sobie dane swoich klientów, takie jak:
  • email,
  • imię,
  • datę dodania,
  • informacje o tym, czy adres e-mail został potwierdzony
i chce te dane zapisać sobie w aplikacji.

Użytkownik musi mieć możliwość:
  • Dodania nowego klienta ze wszystkimi danymi z samej aplikacji.
  • Zapis danych, tak żeby dane były dostępne po zamknięciu i ponownym uruchomieniu aplikacji.
  • Podgląd tych danych w aplikacji.
  • I właśnie możliwość eksportowania danych do formatu CSV, tak żeby można było je podejrzeć w Excelu.
Zadanie nie jest jakoś bardzo skomplikowane. Możemy przejść od razu do implementacji.



Projekt


W poprzednich artykułach pokazywałem Ci, jak tworzyć nowe projekty w Windows Forms i jak używać podstawowych komponentów. W związku z tym, aby nie przedłużać tego materiału przygotowałem już wcześniej projekt od którego będziemy teraz zaczynać implementację. Jeżeli nie wiesz jak założyć nowy projekt i dodać te komponenty, to zajrzyj wcześniej do poprzednich odcinków, gdzie wszystko szczegółowo opisuje.

Pliki CSV w C# - Najważniejsze Informacje - 4

Mamy tutaj kilka komponentów, to znaczy:
1) TextBox, który umożliwia nam wprowadzenie adresu e-mail klienta.
2) TextBox, gdzie będziemy wpisywać imię klienta.
3) DateTimePicker, w celu wprowadzenia daty dodania klienta.
4) CheckBox, który możemy zaznaczyć, jeżeli adres e-mail został potwierdzony.
5) Button, po kliknięciu którego dodamy do listy nowego klienta.
6) Button, po kliknięciu którego zapiszemy dane do pliku CSV.
7) DataGridView w którym wyświetlamy wszystkich klientów z listy mailowej w naszej aplikacji.

Dodatkowo dodałem kilka etykiet w celu poprawienia czytelności aplikacji. Każda kontrolka ma również uzupełnioną właściwość Name, czyli nazwę po której będziemy odnosić się do tych kontrolek w code behind, czyli w kodzie C#.

Przejdźmy do kodu C#.
Mamy tutaj klasę Client, czyli jest to nasz główny model, którego obiekty będziemy zapisywać w pliku.
public class Client
{
    public string Email { get; set; }
    public string Name { get; set; }
    public DateTime AddedDate { get; set; }
    public bool IsConfirmed { get; set; }
}

Składa się ona z 4 właściwości, czyli danych klienta, która będziemy zapisywać.

I mamy jeszcze code behind dla formatki głównej.
public partial class Form1 : Form
{
    private BindingList<Client> _clients = new BindingList<Client>();

    public Form1()
    {
        InitializeComponent();

        dgvClients.DataSource = _clients;
    }

    private void btnAdd_Click(object sender, EventArgs e)
    {
        var client = new Client
        {
            Email = tbEmail.Text,
            Name = tbName.Text,
            AddedDate = dtpAddedDate.Value,
            IsConfirmed = cbIsConfirmed.Checked
        };

        _clients.Add(client);

        ClearData();
    }

    private void ClearData()
    {
        tbEmail.Text = "";
        tbName.Text = "";
        dtpAddedDate.Value = DateTime.Now;
        cbIsConfirmed.Checked = false;
    }

    private void btnSave_Click(object sender, EventArgs e)
    {
    }
}

Mamy tutaj listę _clients, która będzie przechowywała wszystkich klientów w aplikacji. W konstruktorze przypisujemy listę do DataGridView (dgvClients) DataSource w celu wyświetlenia jej na widoku. Ponadto zostały dodane 2 metody, które są wywoływane po kliknięciu kolejno przycisków BtnAdd oraz BtnSave. Jeżeli zostanie kliknięty przycisk BtnAdd, to do listy klientów dodamy nowego klienta z danymi wprowadzonymi na formularzu. Zostanie on również automatycznie wyświetlony w DataGridView. Po dodaniu klienta ustawiamy wartości początkowe dla wszystkich kontrolek formularza. Zobaczmy jak to teraz działa.

Pliki CSV w C# - Najważniejsze Informacje - 5

Jeżeli coś w tym kodzie na ten moment nie jest dla Ciebie jasne, to napisz proszę do mnie na maila lub w komentarzu i wszystko Ci wytłumaczę. Możemy teraz przejść do faktycznej implementacji i działaniu na plikach CSV.



Instalacja biblioteki


Zarówno kod zapisu jak i odczytu danych z pliku CSV możemy sami napisać od zera. Natomiast możemy też ułatwić sobie to zadania i skorzystać z gotowych już bibliotek. Popularną biblioteką do działania na plikach CSV jest biblioteka CsvHelper, z której również skorzystamy. Zainstalujemy tę bibliotekę przez NuGeta.

Pliki CSV w C# - Najważniejsze Informacje - 7

Zapis danych do pliku CSV

Pliki CSV w C# - Najważniejsze Informacje - 8

Zacznijmy od zapisu danych do pliku CSV. W naszym przypadku będziemy zapisywać całą listę obiektów, czyli _clients do pliku np. o nazwie clients.csv.
private void btnSave_Click(object sender, EventArgs e)
{
    using var writer = new StreamWriter(ClientsFileName);
    using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture);
    csv.WriteRecords(_clients);
}

Za pomocą obiektu klasy CsvWriter z biblioteki CsvHelper możemy zapisać dane do pliku. Przy inicjalizacji CsvWriter przekazujemy jako argument obiekt StreamWriter oraz CultureInfo. Następnie wystarczy wywołać metodę WriteRecords i przekazać listę obiektów, które chcemy zapisać w pliku CSV.
private const string ClientsFileName = "clients.csv"

Nazwę pliku będziemy przechowywać w stałej o nawie ClientsFilename, ponieważ będziemy ją jeszcze używać w innych miejscach.

Zobaczmy, czy to faktycznie działa. Uruchomimy teraz aplikację i zobaczymy czy faktycznie został utworzony plik CSV z wcześniej wprowadzonymi danymi.

Pliki CSV w C# - Najważniejsze Informacje - 9 Pliki CSV w C# - Najważniejsze Informacje - 10 Pliki CSV w C# - Najważniejsze Informacje - 11 Pliki CSV w C# - Najważniejsze Informacje - 12

Jeżeli miałbyś taką potrzebę, to również zamiast za każdym razem nadpisywać wszystkie dane, możesz dopisywać tylko nowe. Możesz to zrobić w taki sposób:
private void btnSave_Click(object sender, EventArgs e)
{
    using var stream = File.Open(ClientsFileName, FileMode.Append);
    using var writer = new StreamWriter(stream);
    using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture);
    csv.WriteRecords(_clients);
}

Możesz też przekazać jakieś dodatkowe dane konfiguracyjne inicjalizując nowy obiekt klasy CsvConfiguration.
private void btnSave_Click(object sender, EventArgs e)
{
    var configPersons = new CsvConfiguration(CultureInfo.InvariantCulture)
    {
        HasHeaderRecord = false
    };

    using var stream = File.Open(ClientsFileName, FileMode.Append);
    using var writer = new StreamWriter(stream);
    using var csv = new CsvWriter(writer, configPersons);
    csv.WriteRecords(_clients);
}

Natomiast w naszym przypadku będziemy zawsze nadpisywać wszystkich klientów, także możemy wrócić do pierwszej wersji tej metody.
private void btnSave_Click(object sender, EventArgs e)
{
    using var writer = new StreamWriter(ClientsFileName);
    using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture);
    csv.WriteRecords(_clients);
}

Super, zapis działa prawidłowo. Dodatkowo możemy jeszcze dostosować nasz plik i zmienić np. nazwy nagłówków, kolejność kolumn, czy formatowanie za pomocą mapowania.



Mapowanie


Mapowanie możemy zrobić na 2 sposoby, to znaczy poprzez zmiany bezpośrednio w modelu, dodając odpowiednie atrybuty dla właściwości.
public class Client
{
    [Name("E-mail")]
    [Index(2)]
    public string Email { get; set; }

    [Name("Imię")]
    [Index(1)]
    public string Name { get; set; }

    [Format("dd-MM-yyyy")]
    [Name("Data dodania")]
    [Index(0)]
    public DateTime AddedDate { get; set; }

    [Name("Czy potwierdzony")]
    [Index(3)]
    public bool IsConfirmed { get; set; }
}

Możemy za pomocą atrybutu Name – ustawić nazwę nagłówka.
Dzięki atrybutowi Index - ustalimy kolejność kolumn.
A za pomocą atrybutu Format - sformatujemy w dowolny sposób kolumny.

I to jak najbardziej zadziała i zapisze plik w odpowiedni sposób.

Pliki CSV w C# - Najważniejsze Informacje - 14

Natomiast jest drugi moim zdaniem lepszy sposób, to znaczy zapisywanie konfiguracji w osobnej klasie mapującej. Dzięki temu nie musimy dodawać atrybutów do klasy naszego modelu, który często jest też modelem domenowym, także jest to rozwiązanie takie bardziej uniwersalne i zgodne z najlepszymi praktykami.

Dodamy nową klasę o nazwie ClientMap. Ta klasa musi dziedziczyć po klasie ClassMap i jako typ generyczny wskazujemy klasę do której tworzymy mapowanie. Następnie w konstruktorze konfigurujemy kolumny wywołując odpowiednie metody.
public class ClientMap : ClassMap<Client>
{
    public ClientMap()
    {
        Map(p => p.Email)
            .Index(2)
            .Name("E-mail");

        Map(p => p.Name)
            .Index(1)
            .Name("Imię");

        Map(p => p.AddedDate)
            .Name("Data dodania")
            .TypeConverterOption.Format("dd-MM-yyyy")
            .Index(0);

        Map(p => p.IsConfirmed)
            .Name("Czy potwierdzony")
            .Index(3);
    }
}

Teraz możemy usunąć atrybuty z klasy modelu.
public class Client
{
    public string Email { get; set; }
    public string Name { get; set; }
    public DateTime AddedDate { get; set; }
    public bool IsConfirmed { get; set; }
}

Natomiast przed zapisem musimy zarejestrować to mapowanie.
private void btnSave_Click(object sender, EventArgs e)
{
    using var writer = new StreamWriter(ClientsFileName);
    using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture);
    csv.Context.RegisterClassMap<ClientMap>();
    csv.WriteRecords(_clients);
}

I teraz już działanie będzie identyczne jak wcześniej.

Pliki CSV w C# - Najważniejsze Informacje - 14

Super, możemy teraz przejść do odczytu danych.



Odczyt danych z pliku CSV

Pliki CSV w C# - Najważniejsze Informacje - 15

W naszej aplikacji odczyt danych z pliku CSV chcemy zrobić zaraz po załadowaniu aplikacji. Chcemy, żeby DataGridView został odpowiednio uzupełniony i wyświetlił po starcie aplikacji wszystkie wcześniej wprowadzane dane klientów. Najlepiej taki kod dodać w zdarzeniu Load, który zostanie automatycznie uruchomiony po starcie aplikacji.
private void Form1_Load(object sender, EventArgs e)
{
}

Odczyt danych będzie podobny do zapisu. Tak samo skorzystamy tutaj z biblioteki CsvHelper, która została wcześniej dodana do projektu. Tylko tym razem skorzystamy z klasy CsvReader i metody GetRecords. A tak wygląda cała implementacja:
private void Form1_Load(object sender, EventArgs e)
{
    using var reader = new StreamReader(ClientsFileName);
    using var csv = new CsvReader(reader, CultureInfo.InvariantCulture);
    csv.Context.RegisterClassMap<ClientMap>();
    var clients = csv.GetRecords<Client>().ToList();

    FillTable(clients);
}

private void FillTable(IList<Client> clients)
{
    _clients.Clear();

    if (clients == null || !clients.Any())
        return;

    foreach (var client in clients)
        _clients.Add(client);
}

Zobaczmy czy to faktycznie działa.

Pliki CSV w C# - Najważniejsze Informacje - 16

Jak widzisz, wszystkie dane zostały poprawnie wczytane z pliku CSV.

A tak wygląda nasz plik w Excelu:

Pliki CSV w C# - Najważniejsze Informacje - 14

Możemy jeszcze dodać zabezpieczenie w konstruktorze, które utworzy plik CSV przy pierwszym uruchomieniu aplikacji, tak aby nie został wtedy rzucony wyjątek.
public Form1()
{
    InitializeComponent();

    File.Create(ClientsFileName).Close();

    dgvClients.DataSource = _clients;
}

To w zasadzie wszystko. Taką aplikację można jeszcze bardziej rozwinąć. Można tutaj jeszcze zaimplementować więcej funkcji np. edycję czy usuwanie danych, natomiast nie będziemy się już tym zajmować. W tym odcinku chciałem się skupić tylko na działaniu na plikach CSV.

To wszystkie na dzisiaj. Jeżeli taki artykuł Ci się spodobał, to koniecznie dołącz do mojej społeczności – darmowe zapisy, gdzie będziesz również miał dostęp do dodatkowych materiałów i przede wszystkim bonusów. Do zobaczenia w kolejnym artykule.

Poprzedni artykuł - Za Stary Na Programowanie? Czy Można Zostać Programistą Po 30-stce?
Autor artykułu:
Kazimierz Szpin
Kazimierz Szpin
Programista C#/.NET. Specjalizuje się w ASP.NET Core, ASP.NET MVC, ASP.NET Web API, Blazor, WPF oraz Windows Forms.
Autor bloga ModestProgrammer.pl
Dodaj komentarz
© Copyright 2024 modestprogrammer.pl. Wszelkie prawa zastrzeżone. Regulamin. Polityka prywatności. Design by Kazimierz Szpin