На этом шаге мы рассмотрим средства, используемые для чтения из файла и запись в файл.
Для поддержки операций прямого небуферизованного чтения и записи в дисковые файлы в CFile существуют
функции Read() и Write(), которые обращаются к ReadFile() и WriteFile() - стандартным
функциям Microsoft Windows API. Поскольку прямой доступ к файлу - дело весьма непростое (например,
буферы и смещения указателей надо задавать в единицах, кратных размеру сектора дискового тома), в библиотеке
времени выполнения существуют функции потокового ввода/вывода (stream I/O).
Они позволяют работать с любым форматом данных дисковых файлов: от отдельных символов до больших структур
данных. Также эти функции поддерживают буферизацию ввода/вывода, что иногда позволяет улучшить быстродействие
системы. Вот несколько членов этого семейства: fopen(), fseek(), fread() и fwrite().
Так как Вы программируете на C++, Вы наверняка знакомы с потоковым вводом/выводом с применением классов iostream.
В MFC потоковый ввод/вывод обеспечивается классом CStdioFile. Его функции-члены Read() и Write()
обращаются к библиотечным функциям потокового ввода/вывода. Всегда пользуйтесь гибким и простым в применении CStdioFile,
кроме тех случаев, когда Вам требуется прямой низкоуровневый доступ к файлу.
Файлы, связанные с объектом CStdioFile, открываются либо в текстовом, либо в двоичном режиме. В первом
случае поддерживается специальная обработка пары символов "перевод каретки/перевод строки" (CR/LF).
В этом режиме символ новой строки (0х0А), передаваемый объекту CStdioFile, записывается в файл
как пара байт (0x0D, 0х0А), соответствующих CR/LF, а при считывании эта пара преобразуется
обратно в один байт 0х0А. Чтобы открыть объект CStdioFile как текстовый файл, в функцию Ореn()
нужно передать флаг CFile::typeText следующим образом:
CStdioFile inFile("MyFile.txt", CFile::modeRead | CFile::typeText);
Для задания двоичного режима служит флаг CFile::typeBinary. В этом случае символы новой строки никак не преобразуются.
Для чтения данных из файлового объекта CStdioFile предназначены две функции: Read() и ReadString().
В первую передается указатель на буфер, в который будут помещаться данные, полученные в процессе чтения, а также
целое беззнаковое значение (типа UINT), задающее число байт, которые требуется считать. Read() возвращает
число считанных байт. Если из-за доcтижения конца файла заданное число байт получить не удается, функция возвратит число реально считанных байт.
Ошибка чтения заставляет CFileException возбудить исключение. При записи в текстовом режиме пользуйтесь функцией ReadString(),
которая почти полностью идентична Read(). Отличие ее вот в чем:
- чтение останавливается, если встречается символ новой строки;
- завершающий строку нуль помещается в буфер;
- возвращается указатель на буфер. Если функция достигает конца файла, но при этом ей не удается считать никакой информации,
значение указателя будет равно NULL.
ReadString() позволяет считать отдельную строку текстового файла и возвращает булево значение, указывающее на успех или неудачу операции.
Write() похожа на Read() тем, что также имеет два параметра: буфер с записываемой информацией и число байт, которые требуется записать.
Но Write() не возвращает количество записанных байт. При сбое (им считается и невозможность записать все
указанные байты) CFileException генерирует исключение. При записи в текстовом режиме пользуйтесь функцией CStdioFile::WriteString(),
который позволяет вставлять символ новой строки.
Приведенный ниже код иллюстрирует, как использовать класс CStdioFile для записи и чтения дисковых файлов. Программа открывает файл MyFiIe.bin
в двоичном режиме и считывает его блоками по 10 байт. Каждый блок записывается в новой строке специально
созданного файла Output.txt:
try { CStdioFile inFile("MyFile.bin", CFile::modeRead | CFile::typeBinary); CStdioFile outFile("outfile.txt", CFile::modeCreate | CFile::modeWrite | CFile::typeText); const UINT linelength = 10; TCHAR strBuf[16]; while(inFile.ReadString(strBuf, linelength)) { _tcscat(strBuf, _T("\n")); outFile.WriteString(strBuf); } catch(CFileException * fx) TCHAR buf[255]; fx->GetErrorMessage(buf, 255); AfxMessageBox(buf); }
На следующем шаге мы рассмотрим прямой доступ к файлу.