Pagina personale di:
Carlo Vecchio
appunti di C#, R, SQL Server, ASP.NET, algoritmi, numeri
Vai ai contenuti

C# - Lavorare con i file

C#
Classi
  • C# fornisce le classi ‘File’ e ‘FileInfo’ per leggere e scrivere i file e per recuperarne le proprietà. Le differenze tra le classi ‘File’ e ‘FileInfo’ sono:
    • la classe ‘File’ contiene solo metodi statici e verifica automaticamente i permessi sui file;
    • la classe ‘FileInfo’ deve essere usata con oggetti istanziati dalla classe stessa.

Controllo esistenza di un file / di una directory
  • Per controllare l'esistenza di un file, utilizzare il metodo 'File.Exists()' in 'System.IO'.
  • Esempio:

   bool esiste = System.IO.File.Exists(@"c:\config.sys");

  • Per controllare l'esistenza di una directory, utilizzare il metodo 'Directory.Exists()' in 'System.IO'.
  • Esempio:

  bool esiste = System.IO.Directory.Exists(@"c:\temp");

Controllo validità del nome del file
  • A volte occorre controllare che una stringa sia un nome file valido; infatti alcuni caratteri non possono essere utilizzati nel nome del file.
  • La funzione seguente permette di fare questo controllo.

   public static bool IsValidFilename(string filename)
   {
       foreach (var invalidCharacter in System.IO.Path.GetInvalidFileNameChars())
           foreach (var character in filename)
               if (character == invalidCharacter)
                   return false;
       return true;
   }

Recuperare le informazioni relative a un file
  • Per recuperare le informazioni relative a un file, si può utilizzare la classe ‘FileInfo’ contenuta nel namespace System.IO.
  • Nell’esempio seguente, viene creato un oggetto ‘FileInfo’ e vengono mostrate in Console alcune proprietà.

   System.IO.FileInfo fInfo = new System.IO.FileInfo(@"c:\spool.txt");

   Console.WriteLine("Name:              {0}", fInfo.Name);
   Console.WriteLine("Extension:         {0}", fInfo.Extension);
   Console.WriteLine("FullName:          {0}", fInfo.FullName);
   Console.WriteLine("Exists:            {0}", fInfo.Exists);
   Console.WriteLine("Directory:         {0}", fInfo.Directory);
   Console.WriteLine("DirectoryName:     {0}", fInfo.DirectoryName);
   Console.WriteLine("IsReadOnly:        {0}", fInfo.IsReadOnly);
   Console.WriteLine("Creation Time:     {0}", fInfo.CreationTime);
   Console.WriteLine("LastAccessTime:    {0}", fInfo.LastAccessTime);
   Console.WriteLine("LastWriteTime:     {0}", fInfo.LastWriteTime);
   Console.WriteLine("CreationTimeUtc:   {0}", fInfo.CreationTimeUtc);
   Console.WriteLine("LastAccessTimeUtc: {0}", fInfo.LastAccessTimeUtc);
   Console.WriteLine("LastWriteTimeUtc:  {0}", fInfo.LastWriteTimeUtc);
   Console.WriteLine("Length:            {0}", fInfo.Length);

Attributi di un file
  • È possibile recuperare la versione di un file utilizzando la classe ‘FileVersionInfo’ contenuta in ‘System.Diagnostics’.
  • Esempio:

   FileVersionInfo info = FileVersionInfo.GetVersionInfo(@"C:\...\filename.dll");
   // Restituisce la versione in un'unica stringa
   string s1 = info.FileVersion;
   // Restituisce le quattro versioni
   string s2 = info.FileMajorPart + " - " + info.FileMinorPart + " - " +
               info.FileBuildPart + " - " + info.FilePrivatePart;


Lettura e scrittura di un file testo

  • Nell’esempio seguente, vengono creati un oggetto ‘StreamReader’ (adatto alla lettura di un file testo) e un oggetto ‘StreamWriter’ (adatto alla scrittura di un file testo).
  • Il file che viene letto è ‘c:\temp\input.txt’ e il file che viene scritto è ‘c:\temp\output.txt’. Quest’ultimo contiene il numero di byte di ogni riga del file di input.

   StreamReader fileRead = File.OpenText(@"c:\temp\input.txt");
   StreamWriter fileWrite = File.CreateText(@"c:\temp\output.txt");

   string buffer;

   while ((buffer = fileRead.ReadLine()) != null)
       fileWrite.WriteLine(buffer.Length);

   fileRead.Close();
   fileWrite.Close();

  • Alternativa:

   using (StreamReader fileRead = File.OpenText(@"c:\temp\input.txt"))
   {
       using (StreamWriter fileWrite = File.CreateText(@"c:\temp\output.txt"))
       {
           string buffer;
           while ((buffer = fileRead.ReadLine()) != null)
               fileWrite.WriteLine(buffer.Length);
       }
   }

Lettura e scrittura di un file binario

  • La lettura di un file binario viene eseguita con un oggetto ‘FileStream’.
  • Il metodo ‘Read’ permette di leggere uno stream e memorizzarlo in un array di byte. Bisogna porre attenzione al valore di ritorno del metodo ‘Read’ che rappresenta il numero di byte effettivamente letti; non è detto infatti che questo metodo restituisca tutti i byte richiesti ma potrebbe restituirne di meno.
  • Il ciclo ‘while’ gestisce questa situazione, accodando in un ulteriore array di byte i byte effettivamente letti.

   int count = 0;       // byte che rimangono da leggere        
   int read = 0;        // byte letti
   byte[] buffer;       // buffer di lettura
   byte[] output;       // buffer di output

   FileStream fsRead = new FileStream(@"c:\input.txt", FileMode.Open);
   count = (int)fsRead.Length;
   buffer = new byte[fsRead.Length];
   output = new byte[0];

   while (count > 0)
   {
       read = fsRead.Read(buffer, 0, count);
       Array.Resize(ref output, output.Length + read);
       Array.Copy(buffer, 0, output, output.Length - read, read);
       count -= read;
   }

   fsRead.Close();


  • La scrittura di un file binario viene anch’essa eseguita con un oggetto ‘FileStream’.
  • Vengono scritti un array di byte (con il metodo ‘Write’) e alcuni byte singoli (con il metodo ‘WriteByte’).

   // Prepara un array di 5 byte con i caratteri da 'a' a 'e'.
   byte[] output = new byte[5] {0x61, 0x62, 0x63, 0x64, 0x65};

   FileStream fsWrite = new FileStream(@"c:\temp\output.txt", FileMode.Create);

   // Scrittura dell'array di byte.
   fsWrite.Write(output, 0, output.Length);
   // Scrittura dei byte 0 a 9.
   for (int i = 0; i < 10; i++)
       fsWrite.WriteByte((byte)i);

   fsWrite.Close();

       

Rinominare / Muovere un file

  • Utilizzare la classe 'File' contenuta in 'System.IO'.

   File.Move(@"C:\temp\file1.txt", @"C:\temp\file2.txt");


Cancellazione multipla di file

  • Inserire tra gli using:

   using System.IO;

  • Con le istruzioni seguenti è possibile cancellare tutti i file in una cartella di tipo "txt".

   string[] filePaths = Directory.GetFiles(@"c:\_Canc\", "*.txt");
   foreach (string filePath in filePaths)
       File.Delete(filePath);

Copiare una directory
  • Non essendoci una funzione per copiare una intera directory, comprensiva di tutte le sotto directory, si può utilizzare il codice seguente, modificandone i percorsi nelle prime due righe.

   System.IO.DirectoryInfo directorySorgente = new System.IO.DirectoryInfo(@"c:\a");
   System.IO.DirectoryInfo directoryDestinazione = new System.IO.DirectoryInfo(@"c:\b");

   CopyDirectory(directorySorgente, directoryDestinazione);
   CopyDirectory(directorySorgente, directoryDestinazione);

  • La funzione statica (e ricorsiva) "CopyDirectory" è la seguente.

   static void CopyDirectory(System.IO.DirectoryInfo source, System.IO.DirectoryInfo destination)
   {
       
if (!destination.Exists)
       {
           destination.Create();
       }

       
// Copia tutti i file
       System.IO.
FileInfo[] files = source.GetFiles();
       
foreach (System.IO.FileInfo file in files)
       {
           file.CopyTo(System.IO.
Path.Combine(destination.FullName,
               file.Name));
       }

       
// Processa le sottodirectory
       System.IO.
DirectoryInfo[] dirs = source.GetDirectories();
       
foreach (System.IO.DirectoryInfo dir in dirs)
       {
           
// Directory di destinazione
           
string destinationDir = System.IO.Path.Combine(destination.FullName, dir.Name);

           
// Richiama la funzione stessa ricorsivamente
           CopyDirectory(dir,
new System.IO.DirectoryInfo
(destinationDir));
       }
   }


Lista dei file di una directory
  • Per ottenere la lista dei file appartenenti ad una directory, utilizzare il codice seguente.
  • Le classi utilizzate appartengono al namespace "System.IO.DirecoryInfo".
  • Il metodo "GetFiles()", consente anche il filtraggio dei file.
  • Nell'esempio seguente, tutti i file con estensione "*.txt" sono inseriti in una lista.

   string path = @"C:\Temp";
   DirectoryInfo dInfo = new DirectoryInfo(path);
   FileInfo[] files = dInfo.GetFiles("*.txt");
   foreach (FileInfo file in files)
   {
       lstFiles.Items.Add(file.Name);
   }

Fusione (o merge) di più file
  • In certi casi è utile avere una funzione o un programma, che faccia la fusione di più file.
  • In pratica, dati diversi file, ottenere un unico file con le righe presenti ordinatamente in tutti i file dati.
  • Esempio. Dati i seguenti file con i relativi contenuti:

File 1:
file 1 riga 1
file 1 riga 2
file 1 riga 3

File 2:
file 2 riga 1
file 2 riga 2
file 2 riga 3

File 3:
file 3 riga 1
file 3 riga 2
file 3 riga 3

  • Ottenere il file:

File 'all.txt':
file 1 riga 1
file 1 riga 2
file 1 riga 3
file 2 riga 1
file 2 riga 2
file 2 riga 3
file 3 riga 1
file 3 riga 2
file 3 riga 3

  • Il programma consiste della form seguente, gli oggetti contenuti sono i seguenti:
    • txtDirectory: contiene il path con i file da fondere.
    • txtFilters: contiene le wildcard per indicare quali file fondere.
    • txtFileOutput: contiene il path e il nome del file da creare.
    • btnStart: è il bottone che dà inizio alla fusione dei file.
    • lblMessage: è la label con il messaggio "Waiting".


  • Il codice principale è l'evento del bottone.

   private void btnStart_Click(object sender, EventArgs e)
   {
       lblMessage.Text = "";

       string[] inputFilePaths = Directory.GetFiles(txtDirectory.Text, txtFilters.Text);
       Console.WriteLine("Number of files: {0}.", inputFilePaths.Length);
       using (var outputStream = File.Create(txtFileOutput.Text))
       {
           foreach (var inputFilePath in inputFilePaths)
           {
               using (var inputStream = File.OpenRead(inputFilePath))
               {
                   inputStream.CopyTo(outputStream);
               }
 
               Console.WriteLine("The file {0} has been processed.", inputFilePath);
           }
       }

       lblMessage.Text = "Processed " + inputFilePaths.Length.ToString() + " files.";
   }


© 2022 Carlo Vecchio
Torna ai contenuti