Gestire i file con campi a lunghezza fissa : Parte 3 - La libreria FileHelpers

Ultima parte dell'articolo in cui vedremo il codice necessario per utilizzare la libreria FileHelpers.

il
Sviluppatore / Ingegnere informatico / Funzionario, Collaboratore di IProgrammatori

Questa libreria, gratuita e open source, permette di lavorare facilmente con i file CSV, con i file delimitati e con i file di testo con campi a lunghezza fissa.

Il sito di riferimento è https://www.filehelpers.net/, dove potete trovare tutte le informazioni e gli esempi. Attualmente è in versione 3.5.1 e può essere utilizzata con .NET Framework 4.0 e 4.5, con .NET Standard 2.0, con .NET Core 2.0 e perfino con Mono. In questo articolo proveremo a utilizzarla con .NET 6.0 e in una soluzione di Visual Studio basata sul template “Windows Forms App”, perché in questo momento non ci interessa particolarmente una interfaccia utente particolarmente evoluta, ma solo le operazioni di backend.

Installazione

L’installazione è semplicissima, perché potete utilizzare la Console NuGet che è disponibile in Visual Studio. In sostanza dobbiamo solo:

  1. creare la soluzione in Visual Studio;
  2. selezionare il menu Tools > NuGet Package Manager > Package Manager Console e
  3. eseguire il seguente comando:
 Install-Package FileHelpers

Per l’installazione ci vogliono meno di dieci secondi. A questo punto, tra le dipendenze del progetto troverete anche il nodo Packages > FileHelpers (3.5.1) > Compile Time Assemblies che conterrà il riferimento a FileHelpers.dll che è la libreria da utilizzare.

Sviluppo applicazione

Anche lo sviluppo dell'applicazione è abbastanza semplice, i passaggi da fare sono i seguenti:

  • copiare o spostare il file (noi l'abbiamo chiamato DataFile.txt) contenente i dati nella cartella in cui è contenuto il progetto C#;
  • cliccare sul file dati e nella finestra delle proprietà impostare la voce Copy To Output Directory = Copy always, in modo da includere il file dati nel programma compilato;
  • aggiungere una classe di nome Person e inserire il seguente codice:

using FileHelpers;

[FixedLengthRecord()]
public class Person
{
  [FieldFixedLength(16)]
  public string CF;

  [FieldFixedLength(25)]
  [FieldTrim(TrimMode.Right)]
  public string Cognome;

  [FieldFixedLength(25)]
  [FieldTrim(TrimMode.Right)]
  public string Nome;

  [FieldFixedLength(8)]
  [FieldConverter(ConverterKind.Date, "ddMMyyyy")]
  public DateTime DataNascita;

  [FieldFixedLength(1)]
  public string Genere;

  [FieldFixedLength(1)]
  [FieldNullValue("")]
  public string StatoCivile;

  [FieldFixedLength(2)]
  public string SiglaNazione;

  [FieldFixedLength(13)]
  [FieldConverter(typeof(TwoDecimalConverter))]
  public decimal Reddito;

  [FieldFixedLength(3)]
  [FieldNullValue("")]
  public string Valuta;

  // Convertitore personalizzato:
  internal class TwoDecimalConverter : ConverterBase
  {
    public override object StringToField(string from)
    {
      decimal res = Convert.ToDecimal(from);
      return res / 100;
    }

    public override string FieldToString(object from)
    {
      decimal d = (decimal)from;
      return Math.Round(d * 100).ToString();
    }
  }
}

Come potete vedere, a seconda dei casi ci sono dei descrittori di campo che definiscono la lunghezza in caratteri, eventuali campi con valori nulli, nonché l'applicazione di una funzione di conversione personalizzata;

  • in Form1 aggiungete un pulsante (ridenominato in Apri) e un DataGridView (di nome DataGridView1) e disponeteli come nella Figura 1;

Figura 1 – Disposizione dei controlli, con i dati visualizzati

Fig.1 - Disposizione dei controlli, con i dati visualizzati

  • modificare il codice di Form1 come segue:

using FileHelpers;

namespace Example1
{
  public partial class Form1 : Form
  {
    FileHelperEngine<Person> engine = new FileHelperEngine<Person>();

    public Form1()
    {
      InitializeComponent();
    }

    private void Apri_Click(object sender, EventArgs e)
    {
      this.dataGridView1.ColumnCount = 9;
      this.dataGridView1.Columns[0].HeaderText = "CF";
      this.dataGridView1.Columns[1].HeaderText = "Cognome";
      this.dataGridView1.Columns[2].HeaderText = "Nome";
      this.dataGridView1.Columns[3].HeaderText = "Data nascita";
      this.dataGridView1.Columns[4].HeaderText = "Genere";
      this.dataGridView1.Columns[5].HeaderText = "Stato civile";
      this.dataGridView1.Columns[6].HeaderText = "Sigla nazione";
      this.dataGridView1.Columns[7].HeaderText = "Reddito";
      this.dataGridView1.Columns[8].HeaderText = "Valuta";

      var result = engine.ReadFile("DataFile.txt");

      for (int i = 0; i <= result.GetUpperBound(0); i++)// array rows
      {
        this.dataGridView1.Rows.Add(result[i].CF, result[i].Cognome,
          result[i].Nome, result[i].DataNascita, result[i].Genere,
          result[i].StatoCivile, result[i].SiglaNazione,
          result[i].Reddito, result[i].Valuta);
      }
      this.dataGridView1.AutoResizeColumns();
    }
  }
}

In questo codice invochiamo il motore della libreria per leggere il contenuto del file che viene inserito per righe in oggetti di tipo Person, mentre ogni oggetto Person viene inserito in una riga di un array (possiamo chiamarlo anche "vettore" visto che è monodimensionale).

Il gestore di evento Click del pulsante esegue delle operazioni che sono assolutamente familiari:

  1. imposta il numero di colonne della DataGridView1;
  2. imposta i titoli delle colonne;
  3. legge il file di dati e poi
  4. in un ciclo, legge riga per riga il file e assegna a ciascuna cella della riga il valore corrispondente alla colonna, fino alla fine del file;
  5. infine, fa ridimensionare automaticamente le colonne in base al loro contenuto.

Conclusione

Notate come vengono eliminati gli spazi inutili dai campi cognome e nome, come viene formattata adeguatamente la data di nascita (nel file non ci sono le barre di separazione) e come viene formattato il campo reddito, aggiungendo una virgola che nel file non c'è.

Con alcuni accorgimenti e con le numerose funzionalità della libreria FileHelpers (che in questo articolo abbiamo solamente sfiorato), si possono fare delle operazioni veramente spettacolari in poche righe di codice e, nello stesso tempo, riducendo il tempo di sviluppo e il numero di errori.