Работа с двоичными файлами с использованием функций WinApiСоздание нового файлаДля создания файла используется функция WinApi CreateFile(). System::AnsiString vasFileName; HANDLE hFile; hFile = CreateFile( vasFileName.c_str(), // имя файла, преобразуемое к типу char* GENERIC_READ|GENERIC_WRITE, // доступ для чтения и записи 0, // файл не может быть разделяемым NULL, // дескриптор файла не наследуется CREATE_NEW, // создать новый если не существует FILE_ATTRIBUTE_READONLY, // файл имеет атрибут "только для чтения" NULL // всегда NULL для Windows ); if(hFile != INVALID_HANDLE_VALUE) { //Файл создан CloseHandle(hFile); return; }else { //Файл не создан CloseHandle(hFile); //Здесь можно поместить сообщение об ошибке return; } FILE_ATTRIBUTE определены следующим образом: #define FILE_ATTRIBUTE_READONLY 0x00000001 #define FILE_ATTRIBUTE_HIDDEN 0x00000002 #define FILE_ATTRIBUTE_SYSTEM 0x00000004 #define FILE_ATTRIBUTE_DIRECTORY 0x00000010 #define FILE_ATTRIBUTE_ARCHIVE 0x00000020 #define FILE_ATTRIBUTE_DEVICE 0x00000040 #define FILE_ATTRIBUTE_NORMAL 0x00000080 #define FILE_ATTRIBUTE_TEMPORARY 0x00000100 #define FILE_ATTRIBUTE_SPARSE_FILE 0x00000200 #define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400 #define FILE_ATTRIBUTE_COMPRESSED 0x00000800 #define FILE_ATTRIBUTE_OFFLINE 0x00001000 #define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x00002000 #define FILE_ATTRIBUTE_ENCRYPTED 0x00004000 С помощью этой функции можно открывать уже существующие файлы и консоли для консольных приложений, усекать их, открывать каталоги. Это все задается пятым параметром. Для создания файла этот параметр задается как CREATE_NEW. Вновь создаваемый файл открывается как для чтения, так и для записи, о чем свидетельствует второй параметр функции. Третий и четвертый параметры редко имеют какое-либо практическое применение в Windows 9x и требуются в основном при создании систем с разделением доступа на базе Windows NT. Шестой параметр определяет, какие атрибуты будут установлены для создаваемого файла. В данном случае будет присвоен атрибут Read-Only, позволяющий только чтение файла без записи в него. Windows самостоятельно закрывает все файлы и освобождает дескрипторы, как только завершается выполнение программы, но правило чистоты программирования требует не заставлять думать систему, когда сам знаешь как выполнить то или иное действие. Открытие существующего файлаФункция WinApi OpenFile() открывает файл. Помимо этого, OpenFile() умеет создавать и удалять файлы. Во многом назначения этой функции пересекаются с CreateFile(), и существует в последних версиях WinApi для совместимости с ранними версиями Windows. Поэтому везде, где это возможно, лучше пользовать CreateFile(). System::AnsiString vasFileName="a.000"; HFILE hFile; OFSTRUCT tOfStr; tOfStr.cBytes = sizeof tOfStr; hFile = OpenFile( vasFileName.c_str(), //имя файла, преобразуемое к типу char* &tOfStr, //указатель на буфер с информацией о файле OF_READ); // файл открыт для чтения if(hFile != HFILE_ERROR) { //Файл открыт CloseHandle(HANDLE(hFile)); return; } else { CloseHandle(HANDLE(hFile)); //Здесь может быть помещено сообщение об ошибке return; } Функция OpenFile() принимает всего три аргумента: имя открываемого файла, указатель на структуру OFSTRUCT и флаг режима открытия файла. Структура OFSTRUCT заполняется данными об открытом файле. Она предоставляет такую информацию, как свойства файла, его размер и т. д. typedef struct _OFSTRUCT { BYTE cBytes; BYTE fFixedDisk; WORD nErrCode; WORD Reserved1; WORD Reserved2; CHAR szPathName[OFS_MAXPATHNAME]; }OFSTRUCT, *LPOFSTRUCT, *POFSTRUCT; Третий параметр, флаг открытия файла, устанавливается в режим чтения, чтобы избежать случайного повреждения данных. Разумеется, можно установить и другие режимы:
Удаление файловДля удаления файлов используется функция WinApi DeleteFile(). System::AnsiString vasFileName; DeleteFile( vasFileName.c_str()); // имя удаляемого файла DeleteFile() не удаляет защищенные от записи файлы (READONLY). Копирование и перемещение файловДля копирования используется функция WinApi CopyFile, для перемещения MoveFile(). Определим имена файлов: System::AnsiString vasNameFileFrom; System::AnsiString vasNameFileTo; Функция CopyFile(): if(CopyFile( vasNameFileFrom.c_str(), // имя копируемого файла vasNameFileTo.c_str(), // имя нового файла TRUE)) // если файл уже существует не копировать - true { //Файл скопирован } else { //Сообщение об ошибке копирования } Аналогично CopyFile() действует функция API для переноса файла MoveFile(). if(MoveFile( vasNameFileFrom.c_str(), // имя переносимого файла vasNameFileTo.c_str()) // имя нового файла { //Файл перемещен } else { //Сообщение об ошибке переноса файла } Единственное отличие MoveFile() от CopyFile() - отсутствие третьего параметра, отвечающего за блокировку процесса переноса в случае, если файл уже существует. Чтение информации из файлаДля чтения информации из файла используется функцию Win API ReadFile(), и ряд функций, обеспечивающих ее информацией: HFILE hFile; //Имя читаемого файла System::AnsiString vasFileName="a.000"; DWORD vwCounter; int *virgRDWRBuff; BY_HANDLE_FILE_INFORMATION bhFileInformation; OFSTRUCT tOfStr; tOfStr.cBytes = sizeof tOfStr; //Открываем файл и заполняем информацией tOfStr hFile = OpenFile( vasFileName.c_str(), // имя файла, преобразуемое к типу char* &tOfStr, //указатель на буфер с информацией о файле OF_READWRITE); // файл открыт для чтения и записи if(hFile == HFILE_ERROR) { //Здесь может быть сообщение об ощибке CloseHandle(HANDLE(hFile)); return; } //Теперь можно получить информацию о файле GetFileInformationByHandle ( HANDLE(hFile), // дескриптор файла &bhFileInformation //адрес структуры, в которой сохраняется информация ); //Резервируем память для всего файла обычно размер файла //не больше размера nFileSizeLow объявленного как DWORD int viSize=bhFileInformation.nFileSizeLow/sizeof(int); virgRDWRBuff = (int*) new int[viSize]; //Сдвигаем указатель на нужный байт - сдесь на начало if(_llseek(hFile,0*sizeof(int),0) != (long)(0*sizeof(int))) { CloseHandle(HANDLE(hFile)); //Здесь может быть сообщение об ошибке return; } //Считать данные из файла if(!ReadFile(HANDLE(hFile),virgRDWRBuff, (DWORD)viSize*sizeof(int),&vwCounter,NULL)) { //Здесь может быть сообщение об ошибке } else { if(vwCounter == (DWORD)viSize*sizeof(int)) { //Используем информацию int viRez=virgRDWRBuff[99]; }else { //Здесь может быть сообщение об ошибке } } CloseHandle(HANDLE(hFile)); delete[] virgRDWRBuff; В тексте объявляются две структуры. Первая, BY_HANDLE_FILE_INFORMATION, нужна для хранения полезной информации о файле. Вторая, OFSTRUCT требуется для работы функции API OpenFile(). Далее идет инициализация поля размера этой структуры. Далее - создание буфера, в который будут скопированы данные, считанные из файла. Можно проделать расчет, основанный на размере файла, но можно поступить проще: задать размер принудительно, например 64 Кбайт. Для создания такого буфера можно использовать задание типа new char[0xfffe], выделяющей блок памяти подходящего размера. В конце обработчика необходимо освободить блок памяти операцией delete[]. Само чтение происходит в несколько этапапов: открытие файла, получение его размера, сдвиг на нужную позицию и собственно чтение. Полученный дескриптор функцией OpenFile() открытого файла необходимо передать в качестве параметра для другой функции API - GetFileInformationByHandle(), которая заполняет структуру bhFileInformation типа BY_HANDLE_FILE_INFORMATION, переданную в качестве второго параметра, данными об открытом файле. В этой структуре имеются два поля, хранящие старшие и младшие четыре байта размера файла. Для малого файла хватает и младших четырех байтов. Первые два параметра - это дескриптор читаемого файла и адрес буфера, в который будут считаны данные. Четвертый параметр функции - счетчик байтов, в который ReadFile() записывает количество байтов, считанных из файла. Пятый параметр игнорируется. Обратим внимание на то, что для правильной работы дескриптор файла надо преобразовывать к типу HANDLE. При работе в переменной появятся данные из файла. Запись информации в файлФункция WinApi WriteFile() записывает данные в файл. Она полностью аналогична по используемым параметрам функции ReadFile(). HFILE hFile; System::AnsiString vasFileName="a.000"; DWORD vwCounter; int *virgRDWRBuff; BY_HANDLE_FILE_INFORMATION bhFileInformation; OFSTRUCT tOfStr; tOfStr.cBytes = sizeof tOfStr; //Открываем файл и заполняем информацией tOfStr hFile = OpenFile( vasFileName.c_str(), // имя файла, преобразуемое к типу char* &tOfStr, //указатель на буфер с информацией о файле OF_READWRITE); // файл открыт для чтения и записи if(hFile == HFILE_ERROR) { //Здесь может быть сообщение об ощибке CloseHandle(HANDLE(hFile)); return; } //Теперь можно получить информацию о файле, но понадобиться она //может только для того, чтобы не записать за пределы файла, хотя и //это не страшно, файл просто увеличится в размере GetFileInformationByHandle ( HANDLE(hFile), // дескриптор файла &bhFileInformation //адрес структуры, в которой сохраняется информация ); //Резервировать память для всего файла обычно при записи нет необходимости //так как известно сколько будем писать, например 100 чисел int viSize=100; virgRDWRBuff = (int*) new int[viSize]; //Сдвигаем указатель на нужный байт - сдесь на начало if(_llseek(hFile,0*sizeof(int),0) != (long)(0*sizeof(int))) { CloseHandle(HANDLE(hFile)); //Здесь может быть сообщение об ошибке return; } //Пишем данные в буфер for(int i=0; i < 100; i++) virgRDWRBuff[99-i]=i; //Переносим содержимое буфера в файл if(!WriteFile(HANDLE(hFile),virgRDWRBuff, (DWORD)viSize*sizeof(int),&vwCounter,NULL)) { //Здесь может быть сообщение об ошибке } else { if(vwCounter == (DWORD)viSize*sizeof(int)) { //Запись прошла успешно }else { //Здесь может быть сообщение об ошибке } } CloseHandle(HANDLE(hFile)); delete[] virgRDWRBuff; Пример универсальной функции работы с файламиСледующая функция читает информацию типа int или char из файла, имя которого и директория передается в функцию, или записывает информацию в файл в соответствии с передаваемыми в функцию параметрами. Функция не предполагает чтение всего файла, и написана для случаев когда известно сколько байт предполагается прчитать или записать. ////////////////////////////////////////////////////////////////////// // Функция чтения записи байт из (в) virgRDWRBuff[] // или из (в) vchrgRDWRBuf[] // int virgRDWRBuff[n]; и char vchrgRDWRBuf[n]; должны быть объявлены // вне функции // Функция принимает: // имя директории vasFileDir // имя файла vasFileName // режим чтения записи viRegime 0 - чтение 1 - запись // смещение в элементах int viSeek // число байт для записи/чтения viNumber // что пишем viType 0 - целое 1 - char ///////////////////////////////////////////////////////////////////// int __fastcall TForm1::iRDWR(AnsiString &vasFileDir,AnsiString vasFileName, int viRegime,int viSeek,int viNumber,int viType) { HFILE hFile; AnsiString vasFileName=vasFileDir+"\\"+vasFileName; DWORD dwCounter; OFSTRUCT tOfStr; tOfStr.cBytes = sizeof tOfStr; // Открыть файл hFile = OpenFile(vasFileName.c_str(),&tOfStr,OF_READWRITE); if(hFile == HFILE_ERROR) { CloseHandle(HANDLE(hFile)); //Сообщение об ошибке return 1; } BY_HANDLE_FILE_INFORMATION bhFileInformation; GetFileInformationByHandle ( HANDLE(hFile), // Дескриптор файла // Адрес структуры, в которой сохраняется информация &bhFileInformation ); viRazmer=bhFileInformation.nFileSizeLow; //сдвинуться switch(viType) { case 0: if(_llseek(hFile,viSeek*sizeof(int),0) != (long)(viSeek*sizeof(int))) { CloseHandle(HANDLE(hFile)); //Сообщение об ошибке return 1; } break; case 1: if(_llseek(hFile,viSeek*sizeof(char),0) != (long)(viSeek*sizeof(char))) { CloseHandle(HANDLE(hFile)); //Сообщение об ошибке return 1; } break; } // считать (записать)данные из (в) файл switch(viRegime) { case 1: if(viType == 0) { if(!WriteFile(HANDLE(hFile),virgRDWRBuff, (DWORD)(viNumber*sizeof(int)),&dwCounter,0)) { //Сообщение об ошибке CloseHandle(HANDLE(hFile)); return 1; } }else { if(!WriteFile(HANDLE(hFile),(char far*) vchrgRDWRBuf, (DWORD)(viNumber*sizeof(char)),&dwCounter,0)) { //Сообщение об ошибке CloseHandle(HANDLE(hFile)); return 1; } }//if(viType == 0) break; case 0: if(viType == 0) { if(!ReadFile(HANDLE(hFile),virgRDWRBuff, (DWORD)(viNumber*sizeof(int)),&dwCounter,0)) { //Сообщение об ошибке CloseHandle(HANDLE(hFile)); return 1; } }else { if(!ReadFile(HANDLE(hFile),(char far*) vchrgRDWRBuf, (DWORD)(viNumber*sizeof(char)),&dwCounter,0)) { //Сообщение об ошибке CloseHandle(HANDLE(hFile)); return 1; } }//if(viType == 0) break; }//switch(viRegime) CloseHandle(HANDLE(hFile)); return 0; } |