File e Stream in C++

Ciao, futuri programmatori! Oggi intraprenderemo un'emozionante avventura nel mondo dei file e degli stream in C++. Come il vostro amichevole insegnante di informatica del quartiere, sono qui per guidarvi in questa avventura. Credetemi, alla fine di questa lezione, gestirete i file come dei professionisti!

C++ Files and Streams

Apertura di un File

Iniziamo dagli elementari. Immaginate di avere una cassa del tesoro (che è il nostro file) e di doverla aprire per metterci qualcosa dentro o prenderne qualcosa fuori. In C++, utilizziamo qualcosa chiamato "stream" per interagire con i file.

Per aprire un file, utilizziamo la classe ifstream per la lettura (input) e la classe ofstream per la scrittura (output). Se volete fare entrambe, potete utilizzare la classe fstream.

Ecco come aprire un file:

#include <fstream>
#include <iostream>
using namespace std;

int main() {
ofstream mioFile("tesoro.txt");

if (mioFile.is_open()) {
cout << "La cassa del tesoro è aperta!" << endl;
} else {
cout << "Oh no! Non siamo riusciti ad aprire la cassa del tesoro." << endl;
}

return 0;
}

In questo esempio, stiamo cercando di aprire un file chiamato "tesoro.txt" per la scrittura. La funzione is_open() controlla se il file è stato aperto con successo.

Chiusura di un File

Dopo aver terminato con la nostra cassa del tesoro, è educato (e una buona pratica) chiuderla. In C++, i file vengono chiusi automaticamente quando l'oggetto stream va fuori scope, ma è meglio chiuderli esplicitamente:

mioFile.close();

Scrittura su un File

Ora che abbiamo aperto la nostra cassa del tesoro, mettiamo un po' di tesoro al suo interno! Scrivere su un file è facile come usare l'operatore <<:

ofstream mioFile("tesoro.txt");

if (mioFile.is_open()) {
mioFile << "Monete d'oro: 100" << endl;
mioFile << "Bacchette magiche: 3" << endl;
mioFile << "Uova di drago: 1" << endl;
cout << "Tesoro aggiunto alla cassa!" << endl;
} else {
cout << "Impossibile aprire la cassa del tesoro." << endl;
}

mioFile.close();

In questo esempio, stiamo scrivendo tre righe al nostro file. Ogni operatore << scrive il testo successivo nel file, e endl aggiunge una nuova riga.

Lettura da un File

Leggere da un file è come fare l'inventario della nostra cassa del tesoro. Utilizziamo la classe ifstream e l'operatore >> per leggere da un file:

#include <string>

ifstream mioFile("tesoro.txt");
string riga;

if (mioFile.is_open()) {
while (getline(mioFile, riga)) {
cout << riga << endl;
}
mioFile.close();
} else {
cout << "Impossibile aprire la cassa del tesoro." << endl;
}

Qui, utilizziamo getline() per leggere ogni riga dal file e stamparla sulla console. Il ciclo while continua fino a che non raggiungiamo la fine del file.

Esempio di Lettura e Scrittura

Combiamo la lettura e la scrittura in un esempio più complesso. Creeremo un programma che gestisce il nostro inventario di tesoro:

#include <fstream>
#include <iostream>
#include <string>
using namespace std;

int main() {
// Scrittura sul file
ofstream outFile("inventario.txt");
if (outFile.is_open()) {
outFile << "Monete d'oro: 100" << endl;
outFile << "Bacchette magiche: 3" << endl;
outFile << "Uova di drago: 1" << endl;
outFile.close();
cout << "Inventario salvato!" << endl;
} else {
cout << "Impossibile salvare l'inventario." << endl;
return 1;
}

// Lettura dal file
ifstream inFile("inventario.txt");
string oggetto;
int quantità;

if (inFile.is_open()) {
cout << "Inventario attuale:" << endl;
while (inFile >> oggetto >> quantità) {
cout << oggetto << " " << quantità << endl;
}
inFile.close();
} else {
cout << "Impossibile leggere l'inventario." << endl;
return 1;
}

return 0;
}

In questo esempio, prima scriviamo il nostro inventario su un file, poi lo leggiamo e lo visualizziamo. Notate come utilizziamo >> per leggere parole e numeri separatamente.

Puntatori di Posizione del File

Immagina di leggere un libro e voler tenere traccia di dove ti trovi. I puntatori di posizione del file fanno esattamente questo per i file. Mantengono traccia di dove siamo nel file.

Ecco alcune funzioni utili per lavorare con i puntatori di posizione del file:

Funzione Descrizione
tellg() Restituisce la posizione corrente del puntatore di lettura (per l'input)
tellp() Restituisce la posizione corrente del puntatore di scrittura (per l'output)
seekg() Imposta la posizione del puntatore di lettura
seekp() Imposta la posizione del puntatore di scrittura

Vediamo un esempio:

#include <fstream>
#include <iostream>
using namespace std;

int main() {
fstream file("mappa_del_tesoro.txt", ios::in | ios::out);

if (!file.is_open()) {
cout << "Impossibile aprire la mappa del tesoro!" << endl;
return 1;
}

// Scrittura sul file
file << "X segna il punto!";

// Spostamento all'inizio del file
file.seekg(0, ios::beg);

// Lettura del contenuto
string contenuto;
getline(file, contenuto);
cout << "La mappa dice: " << contenuto << endl;

// Spostamento di 2 caratteri dall'inizio
file.seekp(2, ios::beg);

// Sovrascrittura di parte del contenuto
file << "non segna sempre";

// Spostamento all'inizio e lettura di nuovo
file.seekg(0, ios::beg);
getline(file, contenuto);
cout << "Ora la mappa dice: " << contenuto << endl;

file.close();
return 0;
}

In questo esempio, stiamo scrivendo su un file, poi leggendolo, poi modificandone parte e infine leggendolo di nuovo. È come se stessimo aggiornando la nostra mappa del tesoro!

E là avete tutto, coraggiosi esploratori del regno C++! Avete imparato come aprire casse del tesoro (file), memorizzare il vostro bottino (scrivere dati), fare l'inventario (leggere dati) e anche aggiornare le vostre mappe del tesoro (manipolare i contenuti dei file). Ricordate, la pratica fa l'artigiano, quindi continuate a programmare ed esplorare. Chi sa quali tesori digitali scoprirete下次? Buon coding!

Credits: Image by storyset