Запись и чтение данных в текстовых файлах
Запись и чтение данных в текстовых файлах ничем не отличается от способов ввода-вывода данных с помощью потоков cin и cout. Методы форматирования вывода и вводы данных остаются такими же (флаги форматирования, манипуляторы, функции потоков).
Необходимо помнить, что при использовании операции >> для чтения данных из текстовых файлов, процесс чтения останавливается при достижении пробельного символа (так же как и в потоках cin и cout). Поэтому для чтения строки текста, содержащей несколько слов, необходимо, как и раньше, использовать, например, функцию getline ().
Запись и чтение данных в двоичном режиме
Для работы с файлом в двоичном режиме его необходимо открыть с флагом ios :: binary.
Чтение и запись двоичных данных в этом режиме можно осуществлять двумя способами:
· по одному байту – функции файловых потоков get () и put ();
· блокам определенной длины - функции файловых потоков read () и write ().
Один из вариантов прототипов функций get () и put ()(чаще всего используемый) выглядит так:
ifstream & get (char & ch);
ofstream & put (char ch);
Функция get ()берет один символ из потока ввода, помещает его в символьный параметр ch и возвращает ссылку на поток ввода. Когда достигается конец файла, значение ссылки на поток становится равным 0.
Функция put () помещает символ ch в поток вывода и возвращает ссылку на поток вывода.
В следующей программе с помощью этих функций осуществляется запись в файл массива А из 5 целых чисел, чтение из файла этих данных в массив В и вывод массива В на экран:
Int main ()
{
setlocale (0, "");
//Запись массива А в_файл "E:\test.dat"
ofstream o_File; //Создали поток вывода для записи данных в файл
o_File.open ( "E:\\test.dat", ios::binary ); //Открыли файл
if (! o_File.is_open()) //Проверили, удалось ли открыть файл
{
cout << "Открыть файл не удалось! \n" ;
Return 0;
}
//Записываем данные из массива А в файл
int A[5] = {1, 2, 3, 4, 5};
char *ch = (char *) A; // ch – ссылка на массив А, как на массив символов (байт)
for (int I = 0; I < sizeof(A); ++ I)
o_File.put(ch[I]);
o_File.close(); //Закрываем файл
// Чтение данных из_файла "E:\test.dat" в массив В;
ifstream i_File; //Создали поток ввода для чтения данных из файла
i_File.open ( "E:\\test.dat", ios::binary ); //Открыли файл
if (! i_File.is_open()) //Проверили, удалось ли открыть файл
{
cout << "Открыть файл не удалось! \n" ;
Return 0;
}
// Читаем данные из файла в массив B
int B[5];
ch = (char *) B; // ch – ссылка на массив В, как на массив символов (байт)
int I = 0;
While (i_File)
i_File.get(ch[I++]);
// Предыдущий цикл можно записать короче, например, так:
// while (i_File.get(*ch++);
i_File.close(); //Закрываем файл
// Выводим массив В на экран
for (I = 0; I < 5; ++ I)
cout << B[I] << " ";
cout << endl;
system("pause");
Return 0;
}
А вот как выглядит та же программа при использовании блочных функций чтения и записи (read () и write ()) в двоичном режиме:
Int main ()
{
setlocale (0, "");
//Запись массива А в_файл "E:\test.dat"
ofstream o_File; //Создали поток вывода для записи данных в файл
o_File.open ( "E:\\test.dat", ios::binary ); //Открыли файл
if ( ! o_File.is_open() ) //Проверили, удалось ли открыть файл
{
cout << "Открыть файл не удалось! \n" ;
Return 0;
}
int A[5] = {1, 2, 3, 4, 5};
o_File.write ( (char *) A, sizeof (A) ); //Записываем данные из массива А в файл
o_File.close (); //Закрываем файл
// Чтение данных из_файла "E:\test.dat" в массив В;
ifstream i_File; //Создали поток ввода для чтения данных из файла
i_File.open ( "E:\\test.dat", ios::binary ); //Открыли файл
if ( ! i_File.is_open() ) //Проверили, удалось ли открыть файл
{
cout << "Открыть файл не удалось! \n" ;
Return 0;
}
int B[5];
i_File.read ( (char *) B, sizeof (B) );// Читаем данные из файла в массив B
i_File.close (); //Закрываем файл
// Выводим массив В на экран
for (int I = 0; I < 5; ++ I)
cout << B[I] << " ";
cout << endl;
system("pause");
Return 0;
}
Функции read () и write ()имеют следующие прототипы:
ifstream & read (char * buf, streamsize n);
ofstream & write (const char * buf, streamsize n);
Первый параметр этих функций определяет адрес буфера (некоторого массива символов - байт) для чтения или записи данных в соответствующий файловый поток. Второй параметр задает количество символов – байт, которые необходимо взять из потока или записать в поток (тип данных streamsize –целый тип данных). Размер буфера должен соответствовать значению второго параметра.
Функция write ()обеспечивает запись из буфера, адрес которого указан в первом параметре функции, n символов данных в поток вывода и возвращает ссылку на поток.
Функция read ()обеспечивает запись из потока ввода n символов данных в память по адресу, указанному в первом параметре buf. При достижении конца файла функция возвращает ссылку на поток, равную 0, а фактическое количество взятых из потока символов может быть меньше, чем значение n второго параметра (буфер заполнен не полностью). Фактическое количество считанных из потока ввода символов после выполнения последней операции чтения можно определить с помощью функции потока ввода gcount(). Следующий пример иллюстрирует использование функций блочного чтения и записи данных из произвольного файла.
void FileToScr (char * FileName)
{
fstream File ( FileName, ios::in | ios::binary );
if ( !File ) // Проверили удалось ли открыть файл
{
cout << "Открыть файл не удалось! \n" ;
Return;
}
char Buf [1024];
Do
{
File.read ( Buf, sizeof ( Buf ) );// Читаем данные из файла в буфер
cout.write ( Buf, File.gcount () );// Выводим содержимое буфера на экран
}
While ( File );
cout << endl;
File.close ();
}
Функция FileToScr ()обеспечивает чтение любого указанного файла в двоичном режиме и вывод его на экран в символьном виде с использованием функций блочного чтения и записи. Этот пример показывает, что функции блочного чтения и записи применимы и к стандартным потокам cin и cout (впрочем, как и функции get () и put ()). Ключевым моментом здесь является использование функции потока ввода gcount (). С помощью этой функции удается точно определить количество символов, которое необходимо вывести на экран из буфера после очередной операции чтения из файла.
Как обнаружить конец файла?
При чтении данных из файла обычно используются циклические алгоритмы. При этом возникает задача определить сколько раз необходимо выполнить чтение из файла, чтобы прочитать все данные и не выйти за пределы файла.
Обнаружить конец файла при чтении данных позволяет функция потока:
Bool eof ();
Эта функция не имеет параметров и возвращает значение true, когда достигается конец файла. Пример использования этой функции можно увидеть в одном из предыдущих примеров.
Другой способ определения конца файла основан на том, что функции чтения данных из файла (get (), read ()) при достижении конца файла возвращают нулевую ссылку на поток. Этот способ иллюстрируется в последнем примере.
Дата добавления: 2019-02-07; просмотров: 431;