User Tools

Site Tools


cpp:file_io

Είσοδος και έξοδος αρχείων

Η standard βιβλιοθήκη της C++ παρέχει τις παρακάτω κλάσεις για είσοδο και έξοδο από αρχεία.

  1. ifstream: Κλάση για διάβασμα από αρχείο.
  2. ofstream: Κλάση για γράψιμο σε αρχείο.
  3. fstream: Κλάση για διάβασμα και γράψιμο σε αρχείο.

Οι παραπάνω κλάσεις είναι απόγονοι των κλάσεων istream και ostream. Η χρήση των παραπάνω κλάσεων είναι ανάλογη με τις κλάσεις std::cin και std::cout που επίσης είναι απόγονοι των κλάσεων istream και ostream. Δείτε ενδεικτικά, το παρακάτω παράδειγμα γραφής στο αρχείο hello.txt.

hello_file.cpp
#include <iostream>
#include <fstream>
using namespace std;
 
int main() {
  ofstream myfile;
  myfile.open ("hello.txt");
  myfile << "Hello World!";
  myfile.close();
}

Άνοιγμα αρχείου για ανάγνωση και εγγραφή

Το άνοιγμα των αρχείων γίνεται μέσω της μεθόδου open η οποία προδιαγράφεται παρακάτω:

void open (const char* filename, ios_base::openmode mode);

Η παράμετρος filename είναι ένα αλφαριθμητικό που περιγράφει το σχετικό ή απόλυτο path προς το αρχείο. Η παράμετρος mode μπορεί να πάρει τις ακόλουθες τιμές ή συνδυασμούς τους:

Τιμή Επεξήγηση
ios::in Άνοιγμα για ανάγνωση από το αρχείο.
ios::out Άνοιγμα για εγγραφή στο αρχείο.
ios::binary Άνοιγμα για ανάγνωση ή εγγραφή σε δυαδική μορφή.
ios::app Η θέση εγγραφής τίθεται στο τέλος του αρχείου. Εάν επιχειρήσετε να μεταβάλλετε τη θέση εγγραφής μέσω της συνάρτησης seekp αυτό δεν θα έχει αποτέλεσμα.
ios::ate Θέτει τη θέση εγγραφής στο τέλος του αρχείου. Εάν δεν προσδιοριστεί το συγκεκριμένο flag η θέση εγγραφής τίθεται στην αρχή. Μπορείτε να μεταβάλλετε τη θέση εγγραφής μέσω της συνάρτησης seekp
ios::trunc Εάν το αρχείο υπάρχει ήδη και έχει περιεχόμενο, το υφιστάμενο περιεχόμενο διαγράφεται.

Οι παραπάνω τιμές μπορούν να συνδυαστούν ως εξής:

ofstream lena;
// Open lena.png for writing in binary mode. 
// Truncate file contents if file previously exists.
lena.open("lena.png", ios::out | ios::trunc | ios::binary);

Default τιμές

Οι default τιμές της παραμέτρου mode για τις παραπάνω κλάσεις κλάσεις έχουν ως εξής:

Κλάση Τιμή Παρατήρηση
ofstream ios::out Η τιμή ισχύει ακόμη και εάν αλλάξετε την παράμετρο mode
ifstream ios::in Η τιμή ισχύει ακόμη και εάν αλλάξετε την παράμετρο mode
fstream ios::in | ios::out Η τιμή δεν ισχύει εάν αλλάξετε την παράμετρο mode. Μπορείτε να επαναορίσετε τις τιμές

Παρατηρήστε ότι η μέθοδος open δεν έχει επιστρεφόμενη τιμή για να ελέγξουμε την αποτυχία, ούτε παράγει κάποιο exception. Για να ελέγξετε εάν ένα αρχείο έχει ανοίξει σωστά για διάβασμα ή γράψιμο μπορείτε να χρησιμοποιήσετε τη μέθοδο is_open() ως εξής:

ofstream lena("lena.png", ios::out | ios::trunc | ios::binary);
if (!lena.is_open()) { cerr << "Error while opening \"lena.png\" for writting\n"; }

Παρατηρήστε ότι στο παραπάνω παράδειγμα χρησιμοποιούμε τον κατασκευαστή της κλάσης ofstream αντί για τη μέθοδο open. Τα ορίσματα που λαμβάνει ο κατασκευαστής και η σειρά τους είναι ταυτόσημα με αυτά της μεθόδου open.

Κλείσιμο αρχείου

Για να κλείσετε το αρχείο που προηγουμένως ανοίξατε με τη μέθοδο open αρκεί να καλέσετε τη μέθοδο close ως εξής:

lena.close();

Αρχεία κειμένου

Streams κειμένου είναι εκείνα τα streams που κατά το άνοιγμα του αρχείου δεν έχουν ορισμένο το flag ios::binary. Τα αρχεία αυτά υποθέτουμε ότι περιέχουν μόνο εκτυπώσιμους χαρακτήρες (δηλ. κείμενο) και κατ' επέκταση μπορούμε να τα διαβάσουμε υποθέτοντας ότι οι λέξεις χωρίζονται μεταξύ τους από κενό χαρακτήρα ή χαρακτήρα αλλαγής γραμμής (' ','\t','\n','\x0B','\f','\r') και οι γραμμές χωρίζονται με χαρακτήρα αλλαγής γραμμής ('\r','\n').

Ο τρόπος με τον οποίο γράφετε ή διαβάζετε είναι ο τρόπος που το κάνετε για τη βασική είσοδο και έξοδο.

Γράψιμο σε αρχείο κειμένου
file_write.cpp
#include <iostream>
#include <fstream>
using namespace std;
 
int main (int argc, char *argv[]) {
  string filename;
  cout << "Enter output filename: ";
  cin >> filename;
  ofstream myfile (filename.c_str());
  if (!myfile.is_open()) {
    cout << "Unable to open file " << filename;
    return -1;    
  }
  myfile << "- Which OO language do you prefer?.\n";
  myfile << "- My favorite is C++.\n";
  myfile << "- I prefer Java and Python.\n";
  myfile.close();
}
Διάβασμα από αρχείο κειμένου γραμμή-γραμμή Διάβασμα από αρχείο κειμένου λέξη-λέξη και εκτύπωση κάθε λέξης σε νέα γραμμή
file_read_line_by_line.cpp
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
 
#define MAX_LINE_LEN 1024 // really big!
 
int main () {
  string filename;
  cout << "Enter input filename: ";
  cin >> filename;
  ifstream myfile (filename.c_str());
  char line[MAX_LINE_LEN]; 
 
  if (!myfile.is_open()) {
    cout << "Unable to open file " << filename;
    return -1;    
  }
  while ( myfile.getline (line, MAX_LINE_LEN) )
    cout << line << '\n';   
  myfile.close();  
}
file_read_word_by_word.cpp
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
 
int main () {
  string filename, word;
  cout << "Enter input filename: ";
  cin >> filename;
  ifstream myfile (filename.c_str());
 
  if (!myfile.is_open()) {
    cout << "Unable to open file " << filename;
    return -1;    
  }
  while ( !myfile.eof() )  {
    myfile >> word;
    cout << word << endl; 
  }
  myfile.close();
 
}

Δυαδικά αρχεία

Για δυαδικά αρχεία η ανάγνωση και η εγγραφή με χρήση των τελεστών << (extraction operator) και >> (insertion operator) δεν είναι εφικτή. Για τον λόγο αυτό τα file streams περιέχουν δύο μεθόδους για διάβασμα και γράψιμο δυαδικής πληροφορίας.

istream& read (char* s, streamsize n);
Διάβασμα n στοιχείων τύπου char από το stream και αποθήκευση στο s. Η συνάρτηση επιστρέφει μία αναφορά στο υφιστάμενο stream. Σε περίπτωση που δεν υπάρχουν n διαθέσιμα bytes στο stream αντιγράφει στο s όσα είναι διαθέσιμα και θέτει τα flags failbit και eofbit. Ο αριθμός των bytes που διαβάστηκαν επιστρέφεται από τη συνάρτηση gcount.
ostream& write (const char* s, streamsize n);
Γράψιμο n στοιχείων τύπου char από το s προς το stream.

Δείτε το παρακάτω παράδειγμα ανάγνωσης και εγγραφής από δυαδικό αρχείο. Το πρόγραμμα αντιγράφει το περιεχόμενο ενός υφιστάμενου αρχείου σε ένα άλλο σε τμήματα των SIZE bytes.

binary_copy.cpp
#include <iostream>
#include <fstream>
#include <cmath>
using namespace std;
 
#define SIZE 512
 
int main (int argc, char *argv[]) {  
  string filename;
  cout << "Enter input filename: ";
  cin >> filename;
  ifstream infile(filename.c_str());
  if (!infile.is_open()) {
    cout << "[Read] Unable to open " << filename;
    return -1;    
  }
 
  cout << "Enter output filename: ";
  cin >> filename;
  ofstream outfile(filename.c_str(), ios::trunc);
  if (!outfile.is_open()) {
    cout << "[Write] Unable to open " << filename;
    return -1;    
  }
 
  char buf[SIZE];  
  while(!infile.eof()) {
    infile.read(buf, SIZE);    
    outfile.write(buf, infile.gcount());
  }
  infile.close();
  outfile.close();
}
cpp/file_io.txt · Last modified: 2020/05/17 18:17 (external edit)