Чтение из файла winapi. CreateFile winapi функции

Темы

В предыдущей статье рассматривались принципы работы с дисками и директориями, а именно о файлах было сказано довольно мало. Эта же статья посвящена только операциям, производимым над файлами, такими как чтение, запись, создание, и многим другим, речь о которых пойдет далее.

Необходимость в использовании файлов в собственных приложениях возникает, когда требуется постоянно хранить те или иные данные, полученные в процессе работы приложения и иметь к ним доступ уже после завершения работы программы, при повторном ее запуске.

Как вы, наверное, заметили, подход хранения информации в файлах на разнообразнейших носителях, типов которых в данное время появляется все больше, является очень удобным и в некоторых случаях незаменимым. Характерным и одним из распространенных случаев использования файлов для простых программ, как, в общем-то, и для более сложных приложений, являются случаи хранения в файлах конфигурации программы. То есть хранение данных, отвечающих за то, по каким параметрам будет осуществлено построение внешнего вида окна, например, какие пункты должны присутствовать в меню или в каком-либо элементе управления. В этой статье будет рассмотрен пример загрузки из файла пунктов в элемент управления типа ComboBox.

Теоретические сведения

В Windows предусмотрено два типа работы с файлами: синхронный и асинхронный. Для изучения мы возьмем первый, так как асинхронный применяется редко (удобен для работы с внешними портами компьютеров COM, LPT и т.д.) и в некоторых версиях операционных систем не поддерживается. Так что более удачным будет выбор в пользу использования в разрабатываемом приложении синхронного типа работы с файлами.

Если разбирать сами понятия синхронного и асинхронного типов, то можно сказать, что операции, производимые с файлами, при синхронном режиме будут работать довольно медленно, то есть при начале работы с файлом компьютер будет ждать до того, как работа будет прекращена, и только потом будет продолжена работа приложения. В случае с асинхронным режимом можно работать, параллельно выполняя работу с файлом и совершая необходимые действия, не относящиеся к файлу.

Описание функций

Прежде всего, нужно сказать, что все действия с файлом происходят после использования функции CreateFile(). Эта функция используется для того, чтобы указать, какие права на использование файла необходимо предоставить, а также для создания файлов и работы с внешними портами (как вы, наверное, заметили, функция довольно универсальна и является одной из основных). Все это многообразие действий можно осуществить, передавая в функцию те или иные многочисленные параметры, выбор которых уже зависит от реализации частной задачи. Итак, функция описывается следующим образом:

HANDLE CreateFile (LPCTSTR lpFileName, DWORD dwDesiredAccess,
DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDistribution,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile);

Аргументов у функции действительно много, и их подробный разбор поможет более ясно понять принципы использования самой функции. Первый из них - lpFileName, содержит имя файла, над которым намереваемся совершить действия, второй - dwDesiredAccess отвечает за назначение прав на использование, которые следует предоставить при открытии или создании. Существует всего два значения, которые мы можем передать, - это GENERIC_WRITE для записи и GENERIC_READ для чтения соответственно. Нужно помнить, что эти значения можно комбинировать. Далее идет аргумент dwShareMode, который контролирует открытие файла другими приложениями (пользователями). Опять, как и в предыдущем случае, значений два - FILE_SHARE_READ и FILE_SHARE_WRITE, другие приложения могут только читать из файла в первом случае, когда он используется вашим приложением, и во втором только записывать в файл. Если же не требуется ни того, ни другого, передается нуль. Возможна комбинация из значений. Следующий параметр - lpSecurityAttributes, является указателем на структуру SECURITY_ATTRIBUTES, в которой содержится дополнительная информация о защищенности создаваемого файла.

Чаще всего этот параметр ставится в NULL, без каких-либо потерь в использовании файла. Но если вам все-таки требуется "поставить защиту" на файл, то понадобится и заполнить структуру SECURITY_DESCRIPTOR, указатель на которую содержит SECURITY_ATTRIBUTES. Подробнее об этих структурах рассказывать не имеет смысла из-за того, что их редко используют. После этого идет dwCreationDistribution, обозначающий действия, применяемые к файлу при его открытии или создании. В этот параметр можно передать одно из многих значений: CREATE_NEW - создается новый файл; CREATE_ALWAYS - создается файл с указанным именем, или если такой файл уже создан, то он удаляется и создается заново; OPEN_EXISTING - открывает уже созданный файл; OPEN_ALWAYS - открывает файл с указанным именем (параметр lpFileName), если его нет, то он создается; TRANCATE_EXISTING - открывает файл, после чего происходит удаление его содержимого до нуля байт. Предпоследний аргумент - dwFlagsAndAttributes, указывает, какие атрибуты применять при создании файла. Значений очень много, и они знакомы почти каждому пользователю, для примера приведем чаще всего используемые: FILE_ATRRIBUTE_NORMAL - если вас интересует создание обычного и простого файла, советую использовать этот атрибут;

FILE_ATTRIBUTE_READONLY - только чтение, FILE_ATTRIBUTE_ARCHIVE - архивный файл; FILR_ATTRIBUTE_HIDDEN - скрытый файл. Последние три значения можно комбинировать. Ну и, наконец, последний параметр следует выставить в NULL, он очень редко используется и для учебных целей не представляет интереса. При каждом вызове функции CreateFile() необходимо вызывать проверку на возникновении ошибки, если ошибка возникает, функция возвращает INVALID_HANDLE_VALUE. Если работа функции завершилась удачно, она возвращает указатель на файл (хендл - HANDLE), через который с ним осуществляется дальнейшая работа.

Ясно, что простого открытия или создания файла не достаточно, возникает проблема что-то в него записать или прочитать уже находящуюся в нем информацию. Решение проблемы заключает в себе использование функций ReadFile() - для чтения информации и WriteFile() - для записи информации. Рассмотрим сначала последнюю функцию, хотя, в общем, по синтаксису они похожи, это будет ясно по описанию. Итак, WriteFile() имеет следующий вид:

BOOL WriteFile
(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
LPWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped)

Первый параметр hFile - это хендл, возвращаемый функцией CreateFile() в случае удачного завершения работы.

Второй lpBuffer - это буфер, содержащий информацию, которая будет записана в файл. Что касается третьего nNumberOfBytesToWrite - это число байт, которое мы намереваемся записать, то есть размер буфера lpBuffer в байтах.

Отличие четвертого аргумента lpNumberOfBytesWritten от третьего заключается в том, что в него передается переменная, в которую будет записано фактически, сколько байт данных было записано.

Последний параметр используется при асинхронном способе работы с файлами, использование которого не разбирается в этой статье. Если функция завершилась без ошибок, она возвращает 1, иначе 0.

Функция чтения из файла ReadFile() описывается так:

BOOL ReadFile
(HANDLE hFile, LCVOID lpBuffer,
DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)

Нетрудно заметить, что синтаксис практически полностью идентичен с функцией WriteFile(). Главное отличие заключается именно в самом использовании рассматриваемой функции, а именно, что данные не записываются в файл, а считываются из него. А так, буфер, размер в байтах буфера и число считанных байт используются аналогично.

Допустим, у нас имеется файл, в котором информация записана не подряд одной строкой, а через определенные промежутки. Считывать информацию в этом случае придется, используя такую возможность, как позиционирование в файле, то есть можно указать, с какого места файла будут считываться данные из файла. Осуществить вышеописанные действия позволяет функция SetFilePointer(). Она описана следующим образом:

DWORD SetFilePointer
(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh,
DWORD dwMoveMethod)

Сперва в эту функцию передается хендл уже открытого файла. Во второй параметр lDistanceToMove нужно ввести число, отвечающее, на сколько будет совершено перемещение позиции в файле, с которой впоследствии будет производиться чтение данных. Третий аргумент lpDistanceToMoveHigh напрямую связан со вторым. Обратите внимание на их типы: в первом случае это LONG, а во втором - PLONG, то есть указатель.

Исходя из этого, можно сказать, что при помощи второго параметра можно передвинуть позицию в файле только на 2^32 (4 байта занимает переменная типа LONG), то есть получается, что это максимальный размер файла, с которым возможно работать.

Но в некоторых случая требуется работать с файлами большего размера, для этого-то и предназначен третий параметр, с помощью которого можно изменить позицию в файле на 2^64. Необходимость работать со столь большими файлами возникает очень редко, и поэтому подробно разбирать примеры использования функции SetFilePointer с этим параметром является нерациональным. При вызове функции следует просто передать в этот параметр NULL.

Последний аргумент dwMoveMethod указывает, откуда будет начат отсчет, принимает значения: FILE_BEGIN - начало файла, FILE_CURRENT - с текущего значения, FILE_END - с конца файла. Нужно учесть, что число, на которое следует сдвинуть позицию в файле, может быть отрицательным, это удобно, если отсчет ведется от конца файла. В случае удачного завершения работы функция возвращает новую позицию в файле.

Иногда бывает полезно удалить созданный файл, заканчивая работу программы, например, храня в этом файле промежуточные данные, полученные в процессе работы программы, но совершенно ненужные для постоянного хранения. В этом случае удобно пользоваться функцией:

BOOL DeleteFile (LPCTSTR lpFileName)

В параметр lpFileName просто передается имя файла, который следует удалить. Как и несколько предыдущих функций, при возникновении ошибки функция возвращает 0, иначе 1.

Последней функцией, которую нужно взять на рассмотрение, является функция SetEndOfFile(), позволяющая указать, где следует установить конец файла. Прототип этой функции выглядит так:

BOOL SetEndOfFile (HANDLE hFile)

Нетрудно видеть, что эта функция содержит всего один параметр, а именно хендл открытого файла. Функция возвращает истину, если завершилась удачно, или ложь в случае возникновении ошибки. Концом файла становится то место, в котором находится текущая позиция, установленная функцией SetFilePointer ().

Практика

Как уже упоминалось выше, в практической части этой статьи будет разобран пример написания программы, использующий все разобранные здесь функции. Примерный вид заготовки показан на рисунке 1.

Сразу становится ясно, что код приложения должен содержать оконную функцию, описание класса этого окна, в основном окне должны размещаться элемент управления ComboBox и составленное меню, содержащее пункт Файл и его подпункты "Создать", "Прочитать" и "Удалить".

Всю эту черновую работу по созданию приложения вы должны сделать сами, ведь все перечисленные действия абсолютно не касаются темы, взятой за основу статьи (для облегчения работы можете воспользоваться инструментом App Wizard Win32).

Итак, когда основа приложения уже сделана, перейдем к написанию обработчиков событий для пунктов меню. В функции, обрабатывающей сообщения основного окна, вписываем следующий код:

HANDLE hFile;
// Хендл окна
char cBufferText ;
// Буфер для содержимого текста
int j, i;
// Переменные для цикла
HWND hWnd;
// Идентификатор окна (описывается глобально!)
HWND hCombo;
// Идентификатор списка (описывается глобально!)

В обработчике сообщения, возникающего при нажатии на подпункте "Создать", пишем:

case ID_CREATEFILE:
hFile=CreateFile("proba.zzz", GENERIC_WRITE,
FILE_SHARE_READ,
NULL, CREATE_NEW,
if (INVALID_HANDLE_VALUE ==
hFile)
{
MessageBox (hWnd,"Ошибка при записи файла","Возникла ошибка"MB_OK);
return 0;
}
for(i=0;i<5;i++)
{
for(j=0;j<=10;j++)
cBufferText[j]=NULL;
SetFilePointer
(hFile, 5*i, 0,FILE_BEGIN);
sprintf (cBufferText,"%d",i);
WriteFile (hFile,
cBufferText, sizeof
(cBufferText),
&dwByte, NULL);
}
SetEndOfFile (hFile);
CloseHandle (hFile);
break;

После того как файл создан, по умолчанию в папке, где был запущен исполняемый файл приложения, нужно прочитать информацию из него и занести ее в элемент управления ComboBox, идентификатор которого должен быть описан глобально. Сам элемент, напомню, создается функцией CreateFile(), как и основное окно.

В обработчике сообщения, которое возникает при нажатии на подпункте "Прочитать", вписываем следующий код:

case ID_READFILE:
hFile = CreateFile
("proba.zzz", GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
if(INVALID_HANDLE_VALUE == hFile)
{
MessageBox (hWnd,"Ошибка при открытии файла","Возникла ошибка", MB_OK);
return 0;
}
for(i=0;i<5;i++)
{
SetFilePointer
hFile,5*i,0,FILE_BEGIN);
ReadFile (hFile, cBufferText, sizeof(cBufferText), &dwByte, NULL); SendMessage (hCombo, CB_ADDSTRING,0,(LONG)cBufferText);
}
CloseHandle(hFile); break;

Ну и, наконец, в обработчике подпункта "Удалить" пишем следующие строчки:

case ID_DELETEFILE:
DeleteFile ("proba.zzz");
break;

Вот и вся программа, работу которой вы можете увидеть на рисунке 2. Если открыть созданный в процессе работы приложения файл (после нажатия на подпункт "Создать"), можно увидеть примерно то, что изображено на рис. 3, если, конечно, вы сделали все правильно.

Выводы

В итоге, можно сказать, что доступ к файлам и работа с ними в Windows при синхронном режиме осуществлена довольно просто.

Все сводится к открытию или созданию файла с определенными флагами, осуществлению с ним различных операций и только после этого корректному закрытию, что немаловажно. Если у вас возникнут какие-либо ошибки или вопросы при выполнении практической части и описания теоретической - прошу присылать их на E-mail.


Для создания файла используется функция 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; }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; //Сдвигаем указатель на нужный байт - сдесь на начало 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; }else { //Здесь может быть сообщение об ошибке } } CloseHandle(HANDLE(hFile)); delete virgRDWRBuff;

    В тексте объявляются две структуры. Первая, BY_HANDLE_FILE_INFORMATION, нужна для хранения полезной информации о файле. Вторая, OFSTRUCT требуется для работы функции API OpenFile(). Далее идет инициализация поля размера этой структуры.

    Далее - создание буфера, в который будут скопированы данные, считанные из файла. Можно проделать расчет, основанный на размере файла, но можно поступить проще: задать размер принудительно, например 64 Кбайт. Для создания такого буфера можно использовать задание типа new char, выделяющей блок памяти подходящего размера. В конце обработчика необходимо освободить блок памяти операцией 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; //Сдвигаем указатель на нужный байт - сдесь на начало if(_llseek(hFile,0*sizeof(int),0) != (long)(0*sizeof(int))) { CloseHandle(HANDLE(hFile)); //Здесь может быть сообщение об ошибке return; } //Пишем данные в буфер for(int i=0; i

    Пример универсальной функции работы с файлами

    Следующая функция читает информацию типа 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; }

В лекции рассматривается использование функций библиотеки (C++): CreateFile(), CopyFile(), MoveFile(), DeleteFile(), ReadFile(), WriteFile(), UnlockFile(), LockFile() и CloseHandle().

Материалы по данной теме имеются так же в лекции про файлы .

Содержание лекции:

Создание файлов
Для создания нового или открытия существующего файла используется функция CreateFile. При использовании функции CreateFile необходимо указать, предполагается чтение или запись в файл или и то и другое. Также необходимо указать, необходимые действия в случае наличия файла на диске или его отсутствия (например, перезаписывать файл, если он существует и создавать новый, если – нет). Также функция CreateFile позволяет указать возможность разделения файла с другими приложениями (одновременного чтения/записи нескольких приложений в файл). Если некоторое приложение монополизировало доступ к файлу на чтение и/или запись, то никакое другое приложение не сможет читать и/или писать в файл, пока первое его не закроет.


Операционная система присваивает каждому открытому файлу уникальный идентификатор (дескриптор, file handle), который может быть использован при обращениях к файлу для записи, чтения и получения информации о файле. Дескриптор действителен до тех пор, пока файл не закрыт. Приложение может наследовать дескрипторы файлов от процесса, который его запустил (если дескрипторы наследуемые).


Функция CreateFile среди прочих объектов позволяет обращаться к файлам и каналам (pipes). При обращении к каналам функция CreateFile позволяет создавать клиентское подключение к именованным каналам, находящимся в режиме ожидания подключения. Серверная часть канала создаётся функцией CreateNamedPipe. Одно приложение может создавать множество клиентских подключений к каналу, но к одному экземпляру канала может подключаться только одно приложение (Стоит отметить, что возможно существование нескольких экземпляров именованных каналов с одинаковыми именами).

Функция CreateFile имеет следующий прототип:

HANDLE CreateFile(
LPCTSTR lpFileName, // file name
DWORD dwDesiredAccess, // access mode
DWORD dwShareMode, // share mode
LPSECURITY_ATTRIBUTES lpSecurityAttributes, // SD
DWORD dwCreationDisposition, // how to create
DWORD dwFlagsAndAttributes, // file attributes
HANDLE hTemplateFile // handle to template file
);


Параметры:


lpFileName:
Указатель на строку, содержащую имя объекта для создания или открытия (имя файла, путь к файлу, имя канала и пр.). Если имя задается литеральной константой, то следует поместить её в макрос TEXT() или поставить L перед открывающей кавычкой. Например, TEXT("C:\\tmp.txt") или L"C:\\tmp.txt"


dwDesiredAccess:
Описание желаемого режима доступа к файлу. Существует возможность передачи большого количества различных флагов. Нас интересуют флаги GENERIC_READ, GENERIC_WRITE и их объединение. При доступе к каналам следует учитывать режим создания канала сервером. Если сервер создал канал для записи, то клиент открывает его для чтения и наоборот. Если сервер создал канал для чтения и записи, то клиент может открыть его как для чтения, так и для записи.

dwShareMode:
Определяет режим разделения объекта
0 – приложение открывает файл для монопольного доступа. Последующие обращения на открытие данного файла будут безуспешными, пока данных дескриптор не будет закрыт. Для разделения доступа к файлу могут использоваться следующие ключи (один или вместе):
FILE_SHARE_READ – разрешены лишь последующие операции открытия только на чтение.
FILE_SHARE_WRITE – разрешены лишь последующие операции открытия только на запись.
lpSecurityAttributes
Указатель на сруктуру SECURITY_ATTRIBUTES , которая определяет возможность наследования дескриптора дочерними процессами. Можно передавать NULL – это значит, что дескриптор не может быть наследован (для наших приложений этого достаточно).

dwCreationDisposition:
Определяет то, какие действия необходимо предпринять в случаях, если файл существует и если файл не существует. Этот параметр должен иметь одно из следующих заначений:
Значение Пояснение
CREATE_NEW Создаёт файл. Вызов заканчивается неудачей, если файл существует.
CREATE_ALWAYS Создаёт новый файл. Если файл существует, то его содержимое и атрибуты будут стёрты.
OPEN_EXISTING Открытие файла. Если файл не существует, то вызов закончится неудачей.
OPEN_ALWAYS Открывает файл. Если файл не существует, то он будет создан.
TRUNCATE_EXISTING Открывает файл, размер которого обнуляется. Файл должен открываться как минимум с режимом доступа GENERIC_WRITE. Если файл не существует, то вызов будет неудачен.

dwFlagsAndAttributes:
Позволяет задавать файловые атрибуты (только для чтения, скрытый, системный и пр.). Также позволяет сообщать операционной системе желаемое поведение при работе с файлами. Например, запись в файл без буферизации (FILE_FLAG_NO_BUFFERING и FILE_FLAG_WRITE_THROUGH ); оптимизация для неупорядоченного доступа (FILE_FLAG_RANDOM_ACCESS ); открытие для асинхронного ввода/вывода (FILE_FLAG_OVERLAPPED ).

В озвращаемое значение:
Если вызов успешен, возвращается дескриптор открытого файла. Если вызов неудачен, возвращается константа INVALID_HANDLE_VALUE . Код ошибки можно получить вызовом функции GetLastError. Подробную информацию об ошибке (по её коду) можно получить вызовом функции FormatMessage.

Для копирования файлов используется функция CopyFile :


BOOL CopyFile(
LPCTSTR lpExistingFileName, // имя существующего файла
LPCTSTR lpNewFileName, // имя нового файла
BOOL bFailIfExists // действие, если файл существует TRUE – ошибка
// FALSE - перезаписывать
);


Для переименования файлов и директорий используется функция MoveFile :

BOOL MoveFile(
LPCTSTR lpExistingFileName, // имя файла
LPCTSTR lpNewFileName // новое имя файла
);


В случае успеха возвращается ненулевое значение.

Для удаления существующих файлов используется функция DeleteFile :

BOOL DeleteFile(
LPCTSTR lpFileName // имя удаляемого файла
);

В случае успеха возвращается ненулевое значение.

Чтение/запись в файл:
Каждый открытый файл имеет файловый указатель (file pointer), который указывает позицию следующего файла, который будет записан/прочтен. При открытии файла его файловый указатель перемещается на начало файла. После прочтения/записи очередного файла система перемещает файловый указатель. Файловый указатель можно перемещать, используя функцию SetFilePointer .
Для чтения/записи в файл используются функции ReadFile и WriteFile, при этом необходимо, чтобы файл был открыт на чтение и на запись соответственно.

Функция ReadFile читает из файла указанное количество символов, начиная с позиции, обозначенной файловым указателем. При синхронном (в противоположность асинхронному) чтении файловый указатель сдвигается на фактически прочитанное количество байт.

BOOL ReadFile(
LPVOID lpBuffer, // буфер данных
DWORD nNumberOfBytesToRead, // количество байт для прочтения
LPDWORD lpNumberOfBytesRead, // количество фактически прочитанных байт
// асинхронном чтении
);


Параметры:


hFile:
Дескриптор читаемого файла. Должен быть открыт с доступом GENERIC_READ.


lpBuffer:
Указатель на буфер, принимающий данные из файла.


nNumberOfBytesToRead:
Задаёт количество байт, которые необходимо прочитать из файла.


lpNumberOfBytesRead:
Указатель на переменную, которая принимает количество реально прочитанных байт.


lpOverlapped:


Возвращаемое значение :
Если возвращено ненулевое значение, но прочитано 0 байт, значит файловый указатель стоял на конце файла перед операцией чтения.

Функция WriteFile записывает в файл данные, начиная с позиции, обозначенной файловым указателем. При синхронной (в противоположность асинхронному) записи файловый указатель сдвигается на фактически записанное количество байт.


BOOL WriteFile(
HANDLE hFile, // дескриптор файла
LPCVOID lpBuffer, // буфер данных
DWORD nNumberOfBytesToWrite, // количество байт для записи
LPDWORD lpNumberOfBytesWritten,// количество фактически записанных байт
LPOVERLAPPED lpOverlapped // указатель на структуру, используемую при
// асинхронном чтении
);


Параметры:


hFile:
Дескриптор файла, в который производится запись. Должен быть открыт с доступом GENERIC_WRITE.


lpBuffer:
Указатель на буфер, содержащий данные, которые необходимо записать.


nNumberOfBytesToWrite:
Задаёт количество байт, которые необходимо записать в файл.


lpNumberOfBytesWritten:
Указатель на переменную, которая принимает количество реально записанных байт.


lpOverlapped:
Укзатель на структуру OVERLAPPED. При не асинхронном доступе следует передавать NULL.

Возвращаемое значение:
Если выполнение функции произошло успешно, то возвращается ненулевое значение.


Блокировка файлов:
Т.к. система позволяет более чем одному приложению открывать файл и писать в него, приложения не должны одновременно писать в одну область файла. Эта проблема может быть решена путем временного блокирования части файла. Функция LockFile позволяет приложению получить в монопольное пользования определённое количество байт в файле. Отрезок заблокированных байт может выходить за текущий конец файла. Все попытки сторонних приложений обратиться к заблокированному участку файла потерпят неудачу.
Приложение может файл с помощью функции UnlockFile .

BOOL LockFile(
HANDLE hFile, // дескриптор файла

DWORD nNumberOfBytesToLockLow, // младшее слово длины отрезка
DWORD nNumberOfBytesToLockHigh // старшее слово длины отрезка
);


Параметры:


hFile:
Дескриптор файла, в который производится запись. Должен быть открыт с доступом GENERIC_READ или GENERIC_WRITE (или обоими).

dwFileOffsetLow:
Определяет младшее слово смещения начала блокируемого отрезка относительно начала файла.


dwFileOffsetHigh:
Определяет старшее слово смещения начала блокируемого отрезка относительно начала файла. Не равно нулю, если смещение относительно начала более чем 232 байт.

n NumberOfBytesToLockLow:
Определяет младшее слово длины блокируемого отрезка.


nNumberOfBytesToLockHigh:
Определяет старшее слово длины блокируемого отрезка. Не равно нулю, если длина отрезка более 232 байт или 4 ГБ.


Возвращаемое значение:
Если выполнение функции произошло успешно, то возвращается ненулевое значение.
Блокирование предоставляет процессу монопольный доступ к отрезку файла. Файловые блокировки не наследуются. Остальные процессы не могут ни читать, ни писать в заблокированную часть файла.

Функция UnlockFile позволяет разблокировать участок файла, ранее заблокированный функцией LockFile .

BOOL UnlockFile(
HANDLE hFile, // дескриптор файла
DWORD dwFileOffsetLow, // младшее слово смещения начала отрезка
DWORD dwFileOffsetHigh, // старшее слово смещения начала отрезка
DWORD nNumberOfBytesToUnlockLow, // младшее слово длины отрезка
DWORD nNumberOfBytesToUnlockHigh // старшее слово длины отрезка
);


Параметры данной функции аналогичны параметрам функции LockFile .

Возвращаемое значение:
Если выполнение функции произошло успешно, то возвращается ненулевое значение.
Отрезок файла, который разблокируется функцией UnlockFile должен в точности соответствовать отрезку, заблокированному функцией LockFile. Например, две соседних части файла не могут быть заблокированы по отдельности, а разблокированы как единое целое. Процесс не должен завершать выполнение, имея заблокированные части файлов. Файловый дескриптор, для которого есть заблокированные отрезки, не должен закрываться.

Для оптимального использования ресурсов операционной системы приложение должно закрывать ненужные файлы с помощью функции CloseHandle . Файлы, открытые на момент завершения приложения, закрываются автоматически.

BOOL CloseHandle(
HANDLE hObject // Дескриптор объекта (файла, канала и пр.)
);


Возвращаемое значение:
Если выполнение функции произошло успешно, то возвращается ненулевое значение.

Описание:
function CreateFile(lpFileName: PChar; dwDesiredAccess, dwShareMode: DWORD;
lpSecurityAttributes: PSecurityAttributes; dwCreationDisposition, dwFlagsAndAttributes: DWORD;
hTemplateFile: THandle): THandle;

Создает или открывает следующие объекты и возвращает Хендл (handle), для получения доступа к объекту:
· файлам
· каналам (pipes)
· mailslots

· коммуникационные ресурсы (communications resources)
· Дисковым устройствам (только для Windows NT)
· консолям (consoles)
· папкам (только открытие)

Параметры

lpFileName: Строка которая определяет название объекта для создания или открытия. Если lpFileName - путь, то максимум символов в строке определено константой MAX_PATH.
Windows NT: Можно использовать пути более MAX_PATH знаков, вызывая расширенную (W) версию CreateFile и подставив " \? \ " в Путь. " \? \ " говорит функции выключать парсинг пути. Это позволяет вам использовать пути, которые имеют почти 32 000 Unicode знаков. Функция также работает с именами internet-протокола. " \? \ " игнорируется как часть пути. Например, " \? \C:\myworld\private" будет трансформирован в "C:\myworld\private", а " \? \UNC\tom_1\hotstuff\coolapps" будет трансформирован в " \ tom_1\hotstuff\coolapps".

dwDesiredAccess: Определяет тип доступа к объекту. Приложение может получить доступ по чтению, записи, записи-чтению. Этим параметром может быть любая комбинация следующих флагов:
-0 - Специальный флаг доступа к обьекту. Определяет аттрибуты файла не подсоединяясь к нему, не подсоединяясь к нему.
-GENERIC_READ- определяет доступ по чтению к устройству. Данные могут читаться из файла, а указатель файла может быть перемещен. Объединяется с флагом GENERIC_WRITE для доступа по чтению-записи.

GENERIC_WRITE - определяет, доступ по записи к устройству. Данные могут быть записываться в файл, и указатель файла может быть перемещен. Объединяется с флагом GENERIC_WRITE для доступа по чтению-записи.

dwShareMode: Набор флагов который определяет, как объект может быть разделен(shared). Если dwShareMode - 0, объект не может быть разделен. Последующие операции открытия объекта будут отклонены, пока указатель не будет закрыт.
Чтобы разделить объект, используйте комбинацию следующих флагов:

FILE_SHARE_DELETE - только для Windows NT: Доступ закрыт для всех кроме открывшего, после закрытия указателя файл будет удален.
- FILE_SHARE_READ - Доступ для чтения.
-FILE_SHARE_WRITE - Доступ для записи.

lpSecurityAttributes: Указатель на структуру TSecurityAttributes, которая определяет, может ли возвращенный указатель быть использован процессами-потомками. Если lpSecurityAttributes является пустым, указатель не может быть унаследован.
Windows NT: поле структуры lpSecurityDescriptor определяет описатель безопасности для объекта. Если lpSecurityAttributes является пустым, объект получает описатель по умолчанию. Файловая система должна поддерживать ружим безопасности.

Windows 95: поле lpSecurityDescriptor игнорируется.

dwCreationDistribution: Определяет действие которое надо совершить в случае когда файлы существуют, и какое когда файлы не существуют. Дополнительную информацию см. в Примечаниях. Этим параметром должна быть один из следующих флагов:
-CREATE_NEW создает новый файл. Функция терпит неудачу, если указанный файл уже существует.
-CREATE_ALWAYS создает новый файл. Функция переписывает файл, если он существует.
-OPEN_EXISTING открывает файл. Функция терпит неудачу, если файл не существует.

OPEN_ALWAYS открывает файл, если он существует. Если файл не существует, функция создает файл.
-TRUNCATE_EXISTING открывает файл. После того файл открывается его размер обнуляется. Процесс запроса должен открыть файл с по крайней мере с GENERIC_WRITE доступом. Функция терпит неудачу, если файл не существует.

DwFlagsAndAttributes: Определяет признаки файла и флаги для файла.
Любая комбинация следующих признаков приемлема. Все признаки файла перекрывают FILE_ATTRIBUTE_NORMAL. См. FILE_ATTRIBUTE_.

Любая комбинация следующих флагов приемлема для использования.
- FILE_FLAG_WRITE_THROUGH - говорит системе чтобы при записи в кэш сразу шла запись на диск.
- FILE_FLAG_OVERLAPPED - говорит системе возвращать указатель даже если действие еще не завершено. Без этого флага функции ReadFile, WriteFile, ConnectNamedPipe, и TransactNamedPipe, которые занимают существенное время, возвращают ERROR_IO_PENDING. Когда действие закончено, вызывается событие указывающее об этом.Когда Вы определяете FILE_FLAG_OVERLAPPED, ReadFile, и функции WriteFile должны определить структуру TOverlapped.Когда FILE_FLAG_OVERLAPPED определен, операционная система не не обслуживает указатель файла. Позицию указателя файла нужно передать как часть параметра lpOverlapped (указывающий на структуру TOverlapped) к функциям WriteFile и ReadFile.

Этот флаг также позволяет выполняться более чем одному действию с указателем файла (например одновременный читать и писать).
- FILE_FLAG_NO_BUFFERING - Инструктирует операционную систему открывать файл без промежуточного буфера или кэширования.
- FILE_FLAG_RANDOM_ACCESS - Указывает, что к файлу обращаются беспорядочно. Windows может использовать это как намек, чтобы оптимизировать кэширование файла.
- FILE_FLAG_SEQUENTIAL_SCAN - Указывает, что к файлу нужно обратиться последовательно с начала до конца. Windows может использовать это как намек, чтобы оптимизировать кэширование файла.

FILE_FLAG_DELETE_ON_CLOSE - Указывает, что операционная система должна удалить файл немедленно после того, как все его указатели будут закрыты.
- FILE_FLAG_BACKUP_SEMANTICS - только для Windows NT: Указывает, что файл открывается или создается для резервирования или восстанавления. Операционная система гарантирует, что процесс запроса отвергает проверку безопасности файла. Уместные разрешения - SE_BACKUP_NAME, и SE_RESTORE_NAME.
FILE_FLAG_POSIX_SEMANTICS - Указывает, что к файлу нужно обратиться согласно правилам POSIX.

Если функция CreateFile открывает клиент канала, параметр dwFlagsAndAttributes может также содержать Security Quality of Service information. Когда приложение запрашивает флаг SECURITY_SQOS_PRESENT, параметр dwFlagsAndAttributes может содержать один или больше следующих флагов:
- SECURITY_ANONYMOUS - определяет Анонимнго клиента(Anonymous).
- SECURITY_IDENTIFICATION - определяет Идентифицируемого клиента(Identification).
- SECURITY_IMPERSONATION определяет клиента уровня IMPERSONATION.

SECURITY_DELEGATION - определяет клиента уровня DELEGATION.
- SECURITY_CONTEXT_TRACKING - определяет, что способ отслеживания безопасности является динамическим.
- SECURITY_EFFECTIVE_ONLY - определяет, что только позволенные аспекты содержания безопасности клиента доступны серверу. Если Вы не определяете этот флаг, все аспекты содержания безопасности клиента доступны. Этот флаг позволяет клиенту ограничивать группы и привилегии которые сервер может использовать при исполнении запроса клиента.

hTemplateFile - Определяет указатель с доступом GENERIC_READ к файлу шаблона. Файл шаблона задает признаки файла и расширенные признакаки для создаваемого файла.
Windows 95: Этот флаг должен быть равен NULL. Если Вы установливаете указатель под Windows 95, запрос терпит неудачу, и GetLastError возвращает ERROR_NOT_SUPPORTED.

Возвращаемые значения
Если функция преуспевает - открытый указатель к файлу. Если указанный файл существовал до запроса функции и dwCreationDistribution - CREATE_ALWAYS или OPEN_ALWAYS, запрос к GetLastError возвращает ERROR_ALREADY_EXISTS. Если файл не существовал перед запросом, GetLastError возвращает ноль.

Если функция терпит неудачу - INVALID_HANDLE_VALUE. Чтобы получить расширенную информацию об ошибке, вызовите GetLastError.

Примечания
Используйте функцию CloseHandle, чтобы закрыть указатель объекта, возвращенную CreateFile.
Как отмечено выше, определяя ноль для dwDesiredAccess функция позволяет узнать признаки устройства, фактически не обращаясь к устройству. Этоо полезено, например, если функция хочет узнать размер дискеты, и поддерживаемые форматы, при этом не имея дискеты в дисководе.

Файлы
При создании нового файла, функция CreateFile исполняет следующие действия:
· объединяет признаки файла и флаги, указанные dwFlagsAndAttributes с FILE_ATTRIBUTE_ARCHIVE.
· устанавливает длину файла на ноль.
· копирует расширенные признаки, заданные файлом шаблона к новому файлу, если параметр hTemplateFile определен.

При открытии существующего файла, CreateFile исполняет следующие действия:
· объединяет флаги файла, указанные dwFlagsAndAttributes с существующими признаками файла. CreateFile игнорирует признаки файла, указанные dwFlagsAndAttributes.

· устанавливает длину файла согласно флагу dwCreationDistribution.
· игнорирует параметр hTemplateFile.
· игнорирует параметр lpSecurityDescriptor структуры TSecurityAttributes, если lpSecurityAttributes параметр не является NULL. Другие параметры структуры используются. Параметр bInheritHandle - единственный способ указать, может ли указатель файла быть унаследованным.

Если Вы пытаетесь создавать файл на сменном накопителе(дискета, CD-ROM) который не имеет вставленного носиеля, система показывает окно сообщения, прося пользователя вставить диск или компакт-диск, соответственно. Чтобы препятствовать системе показывать это окно сообщения, вызовите функцию SetErrorMode с флагом SEM_FAILCRITICALERRORS.

Каналы(Pipes)
Если CreateFile открывает клиента, функция использует любой открытый клиент, которая находится в состоянии приема. Процесс открытия может дублировать указатель так много раз как требуется, но, когда-то открытый клиент не может быть открыт на другого клиента.

Mailslots
Если CreateFile открывает клиента-mailslot, функция возвращает INVALID_HANDLE_VALUE, если mailslot-клиент пытается открывать локальный mailslot прежде, чем mailslot-сервер создал его с функцией CreateMailSlot.

Ресурсы Коммуникаций
Функция CreateFile может создать указатель к ресурсу коммуникаций, типа последовательного порта COM1. Для ресурсов коммуникаций, dwCreationDistribution параметром должен быть OPEN_EXISTING, и hTemplate параметр должен быть NULL. Указатель можен быть открыть для записи, чтения, чтения-записи.

Дисковое устройство
Windows NT: Вы можете использовать функцию CreateFile, чтобы открыть дисковод. Функция возвращает указатель на дисковые устройства. Указатель может использоваться с функцией DeviceIOControl. Следующие требования должны быть выполнены:

· вызывающий должен иметь привилегии администратора.
· строка lpFileName должна иметь форму \.\PHYSICALDRIVEx, чтобы открыть жесткий диск x. Номера жесткого диска начинаются с нуля. Например: \.\PHYSICALDRIVE2 - получает указатель на третий физический диск на компьютере пользователя.
· строка lpFileName должна быть \.\x: чтобы открыть накопитель на гибких дисках. Например: \.\A: - получает указатель,на диск А. \.\C: - получает указатель,на диск C.
Windows 95: Эта функция не открывает логическое устройство. В Windows 95 это вызовет ошибку.

· параметр dwCreationDistribution должен иметь флаг OPEN_EXISTING.
· при открытии дискеты или жесткого диска, Вы должны установить флаг FILE_SHARE_WRITE в параметре dwShareMode .

Консоли (consoles)

Функция CreateFile может создать указатель ввод консоли (CONIN$). Если процесс имеет открытый указатель к нему в результате наследования или дублирования, то функция может также создать указатель на активный буфер экрана (CONOUT$). Процесс запроса должен быть присоединен к унаследованной консоли или один размещенный функцией AllocConsole. Для указателей консоли, установите параметры CreateFile следующим образом:

lpFileName - используют CONIN$, чтобы определить ввод консоли и CONOUT$, чтобы определить вывод консоли.
CONIN$ получает указатель на входной буфер консоли, даже если функция SetStdHandle переадресовывала стандартный указатель. Чтобы получить стандартный указатель, используйте функцию GetStdHandle.
CONOUT$ получает указатель на активный буфер экрана, даже если SetStdHandle переадресовывала стандартный указадель вывода. Чтобы получить стандартный указатель выводо используйте GetStdHandle.

dwDesiredAccess лучше устанавливать GENERIC_READ | GENERIC_WRITE, но любой может ограничить доступ.
dwShareMode, если процесс запроса унаследовал консоль или если дочерний процесс способен получить доступ, этот параметр должен быть FILE_SHARE_READ | FILE_SHARE_WRITE.
lpSecurityAttributes, если Вы хотите, чтобы консоль была унаследована,параметр bInheritHandle структуры TSecurityAttributes должен быть True.
dwCreationDistribution Вы должны определить OPEN_EXISTING при использовании CreateFile, чтобы открыть консоль.

dwFlagsAndAttributes игнорируется.
hTemplateFile игнорируется.

Следующий список показывает эффекты различных назначений fwdAccess и lpFileName.

lpFileName fwdAccess Результат
CON GENERIC_READ Открывает консоль для ввода
CON GENERIC_WRITE Открывает консоль для вывода
CON GENERIC_READ\GENERIC_WRITE Windows 95:Терпит неудачу; GetLastError возвращает ERROR_PATH_NOT_FOUND.
Windows NT: Терпит неудачу; GetLastError возвращает ERROR_FILE_NOT_FOUND.
Папки
Вызов функции CreateFile не может создать папку, чтобы создать папку надо вызвать CreateDirectory или CreateDirectoryEx.
Windows NT:Вы можете получить указатель к папку, подставив флаг FILE_FLAG_BACKUP_SEMANTICS . Указатель папки можно передать некоторым функциям Win32 вместо указателя файла. Некоторые файловые системы, типа NTFS, поддерживают сжатие для индивидуальных файлов и папок. На устройствах, форматированных для такой файловой системы, новая папка унаследует признак сжатия ее родительской папки.

Материал взят из:
Русская спpавка по Windows API

WinAPI. Функции работы с файлами. Часть 4 :

Заканчиваем изучать WinAPI работы с фалами и дисками. Это последняя статья, потому что в следующий раз мы перейдём к рассмотрению другой группы WinAPI функций. Я постарался дать тебе максимум инфе о основных API для работы с файлами. Надеюсь, что я работал не зря.

Сегодня ты узнаешь про:

ReadFile

Функция читает из файла блок данных начиная с текущей позиции. После прочтения блока, позиция переносится в конец прочитанного блока.

Объявление:

Для С/С++ BOOL ReadFile(HANDLE hFile, // Указатель на открытый файл LPVOID lpBuffer, // Указатель на буфер, куда поместится прочитанный блок DWORD nNumberOfBytesToRead, // количество прочитанных байтов LPDWORD lpNumberOfBytesRead,// указатель на число прочитанных данных LPOVERLAPPED lpOverlapped // указатель на структуру OVERLAPPED); Для Delphi function ReadFile(hFile: THandle; // Указатель на открытый файл var Buffer; // Указатель на буфер, куда поместится прочитанный блок nNumberOfBytesToRead: DWORD; // количество прочитанных байтов var lpNumberOfBytesRead: DWORD; // указатель на число прочитанных данных lpOverlapped: POverlapped // указатель на структуру OVERLAPPED): BOOL; stdcall;

RemoveDirectory

Функция удаляет директорию. Если внутри есть хотя бы один файл или другая директория, то произойдёт ошибка. Удаление возможно только пустой директории.

Существует в: Win NT, Win9x, Win32s.

Для С/С++ объявлена в winbase.h. Для Delphi в модуле windows.

Объявление:

Для С/С++ BOOL RemoveDirectory(LPCTSTR lpPathName // Указатель на путь директории); Для Delphi function RemoveDirectory(lpPathName: PChar// Указатель на путь директории): BOOL; stdcall;

Если всё ничтяк, то функция вернёт TRUE.

Пример использования: RemoveDirectory("с:\Windows");

SetCurrentDirectory

Функция изменяет текущую директорию на указанную. Это значит, что когда ты будешь использовать другие функции работы с файлами, и не указывать путь, то ОС будет искать файл в этой директории.

Существует в: Win NT, Win9x, Win32s.

Для С/С++ объявлена в winbase.h. Для Delphi в модуле windows.

Объявление:

Для С/С++ BOOL SetCurrentDirectory(LPCTSTR lpPathName // Указатель на строку, содержащую путь); Для Delphi function SetCurrentDirectory(lpPathName: PChar // Указатель на строку, содержащую путь): BOOL; stdcall;

Если всё ничтяк, то функция вернёт TRUE.

SetEndOfFile

Функция делает текущую позицию файла концом файла. Если тебе нужно сократить размер файла, то вызови эту функцию, установи курсор в необходимую позицию и вызови эту функцию.

Существует в: Win NT, Win9x, Win32s.

Для С/С++ объявлена в winbase.h. Для Delphi в модуле windows.

Объявление:

Для С/С++ BOOL SetEndOfFile(HANDLE hFile // Указатель на открытый файл); Для Delphi function SetEndOfFile(hFile: THandle // Указатель на открытый файл): BOOL; stdcall;

Если всё ничтяк, то функция вернёт TRUE.

SetFileAttributes

Функция позволяет устанавливать на файл атрибуты.

Существует в: Win NT, Win9x, Win32s.

Для С/С++ объявлена в winbase.h. Для Delphi в модуле windows.

Объявление:

Для С/С++ BOOL SetFileAttributes(LPCTSTR lpFileName, // Путь к файлу DWORD dwFileAttributes // Будущие атрибуты файла); Для Delphi function SetFileAttributes(lpFileName: PChar; // Путь к файлу dwFileAttributes: DWORD // Будущие атрибуты файла): BOOL; stdcall;

С первым параметром всё ясно. Это просто путь к файлу. А вот второй параметр это атрибуты. Они могут быть в виде сочетания следующих флагов:

  • FILE_ATTRIBUTE_ARCHIVE - атрибут архивного файла.
  • FILE_ATTRIBUTE_HIDDEN - атрибут спрятанного файла.
  • FILE_ATTRIBUTE_NORMAL - атрибут нормального файла.
  • FILE_ATTRIBUTE_OFFLINE - указывает на то, что данные файла не доступны и находятся на отключённом устройстве
  • FILE_ATTRIBUTE_READONLY - атрибут файла только для чтения.
  • FILE_ATTRIBUTE_SYSTEM - атрибут системного файла.
  • FILE_ATTRIBUTE_TEMPORARY - атрибут временного файла.

Если всё ничтяк, то функция вернёт TRUE.

SetFilePointer

Функция устанавливает позицию в файле. Например, если ты хочешь прочитать данные из файла начиная с какой-то позиции, то ты должен воспользоваться этой функцией, чтобы выставить позицию, а потом прочитать данные начиная с этой позиции.

Существует в: Win NT, Win9x, Win32s.

Для С/С++ объявлена в winbase.h. Для Delphi в модуле windows.

Объявление:

Для С/С++ DWORD SetFilePointer(HANDLE hFile, // Указатель на открытый файл LONG lDistanceToMove, // количество байт, на которые надо передвинуться PLONG lpDistanceToMoveHigh, // Второй байт, указывающий количество байт DWORD dwMoveMethod //Откуда нужно начинать двигаться); Для Delphi function SetFilePointer(hFile: THandle; // Указатель на открытый файл lDistanceToMove: Longint; // количество байт, на которые надо передвинуться lpDistanceToMoveHigh: Pointer; // Второй байт, указывающий количество байт dwMoveMethod: DWORD //Откуда нужно начинать двигаться): DWORD; stdcall;

Первый параметр - указатель на открытый файл. Второй и третий параметры определяют количество байт, на которые надо передвинуться. Последний параметр - это флаг определяющий откуда надо начинать двигаться:

  • FILE_BEGIN - Передвинуться от начала файла вперёд.
  • FILE_CURRENT - Передвинуться начиная от текущей позиции вперёд.
  • FILE_END - Передвинуться от конца файла к началу.

Если всё ничтяк, то функция вернёт младший байт установленной позиции.

Если ты хочешь узнать текущую позицию файла, то можешь смухлевать, вызвав функцию с такими параметрами: SetFilePointer(h,0,0, FILE_CURRENT). Этим ты заставляешь передвинутся на 0 байтов от текущей позиции. Передвижения не произойдёт, но функция вернёт новую позицию файла, то есть текущую.

SetVolumeLabel

Функция устанавливает метку тома

Существует в: Win NT, Win9x.

Для С/С++ объявлена в winbase.h. Для Delphi в модуле windows.

Объявление:

Для С/С++ BOOL SetVolumeLabel(LPCTSTR lpRootPathName, // Указатель на имя тома LPCTSTR lpVolumeName // Метка тома); Для Delphi function SetVolumeLabel(lpRootPathName: PChar; // Указатель на имя тома lpVolumeName: PAnsiChar// Метка тома): BOOL; stdcall;

Если всё ничтяк, то функция вернёт TRUE.

WriteFile

Функция производит запись блока данных начиная с текущей позиции в файле.

Существует в: Win NT, Win9x, Win32s.

Для С/С++ объявлена в winbase.h. Для Delphi в модуле windows.

Объявление:

Для С/С++ BOOL WriteFile(HANDLE hFile, // Указатель на открытый файл LPCVOID lpBuffer, // Указатель на данные для записи DWORD nNumberOfBytesToWrite, // Количество записанных байт LPDWORD lpNumberOfBytesWritten,// Указатель на количество записанных байт LPOVERLAPPED lpOverlapped // Указатель на структуру OVERLAPPED); Для Delphi function WriteFile(hFile: THandle; // Указатель на открытый файл const Buffer; // Указатель на данные для записи nNumberOfBytesToWrite: DWORD; // Количество записанных байт var lpNumberOfBytesWritten: DWORD; // Указатель на количество записанных байт lpOverlapped: POverlapped // Указатель на структуру OVERLAPPED): BOOL; stdcall;

Если всё ничтяк, то функция вернёт TRUE.

На этом я заканчиваю рассмотрения функций для работы с файлами.