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);
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");
System.IO.DirectoryInfo directoryDestinazione = new System.IO.DirectoryInfo(@"c:\b");
CopyDirectory(directorySorgente, directoryDestinazione);
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.";
}