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

При использовании имен файлов в программах на языках C, C++ следует помнить об одном соглашении – спецификация файла задается строкой, в которой знак "обратного слэша" заменяется удвоенным обратным слэшем:
char namef[]="c:\\bc\\bin\\bc.exe"
Файловая подсистема обеспечивает возможность создания новых
подкаталогов, создания и удаления файлов, копирования и переименования
файлов. Средства операционной системы обеспечивают некоторую защиту
наборов данных – например, системные и
Оценивая ключевые аспекты процесса обмена данными, можно сказать, что работа с файлами, в основном, ограничивается тремя-четырьмя операциями:
Несмотря на кажущуюся простоту процесса обмена данными, файловые операции достаточно сложны в освоении. Во-первых, не следует забывать о трех уровнях доступа к файловым данным (BIOS, операционная система, система программирования). Во-вторых, операционные системы MS-DOS, Windows и Linux пытаются достичь совместимости в выполнении файловых операций. Все это приводит к появлению довольно большого количества различных обслуживающих программ. Так, системная библиотека BC 3.1 насчитывает более 120 функций для работы с файлами и свыше 60 констант, задающих режимы работы файловых процедур.
При работе с файлами приходится учитывать многочисленные форматы
представления данных того или иного типа на разных носителях
информации. Так, например, цепочка из k символов, представляющая
текстовую строку, может храниться в одном из следующих форматов:
"S1S2S3...Sk" (переменное число символов, заключенных в одинарные или двойные кавычки);kS1S2...Sk ( k – однобайтовый или двухбайтовый счетчик числа символов, предшествующий тексту);S1S2...Sk\0 ( \0 – однобайтовый признак конца строки, расположенный вслед за последним символом текста);S1S2...Sk 0D 0A (двухбайтовый признак конца строки, 0D –"возврат каретки", 0A – "перевод строки").Числовая информация может быть записана в дисковый файл либо в машинном формате (а в языках С, С++ количество разных типов числовых данных достигает десятка), либо с предварительным преобразованием из машинного представления в символьное.
Кроме числовых и текстовых данных в файлах может храниться
информация и другого происхождения. Например, графические изображения,
которые в процессах обмена данными выступают как двоичные коды,
условно разделенные на байты. Естественно, что на содержимое этих
байтов нельзя реагировать так же, как на некоторые
Далее, существует несколько способов доступа к файловым данным, из
которых на практике чаще всего используют два – последовательный и произвольный. Последний иногда называют прямым ( ) или случайным ( ).
Последовательный доступ при записи на диск характерен тем, что очередная записываемая порция пристраивается в хвост к предыдущей. Размеры смежных порций при этом могут оказаться разными по длине. При чтении такой набор данных начинает извлекаться с самой первой порции и очередность считываемых данных повторяет их последовательность во время записи.
Файлы с произвольным доступом состоят из данных, разбитых на порции фиксированной длины. При этом имеется возможность записывать или читать данные в произвольном порядке, указывая дополнительно номер нужной порции.
Наконец, необходимо учитывать и способы разделения отдельных числовых или символьных значений в дисковых наборах данных. В некоторых ситуациях роль таких разграничителей могут выполнять кавычки, запятые, пробелы и различные управляющие байты ( "табуляторный пропуск", "возврат каретки", "перевод строки", "признак конца файла" ). В других ситуациях для каждого данного может быть выделено поле фиксированной длины.
Системы программирования BC 3.1 и BCB поддерживает работу с файлами и потоками, данные в которых представлены либо в символьном, либо в двоичном формате.
Содержимое текстового файла очень напоминает то, что мы видим на экране дисплея, когда программа отображает на нем результаты вычислений. Разница только в том, что на экран дисплея только выводят, а текстовый файл можно использовать как хранилище информации, в которое не только пишут, но из которого еще и читают.
Текстовые файлы относятся к файлам последовательного доступа, т.к.
единицей хранения информации в них являются строки переменной длины.
Каждая строка заканчивается специальным признаком, обычно его функцию
выполняет пара символов 0D0A – "возврат каретки" и "перевод строки".
Самым важным преимуществом текстовых файлов является универсальность
формата хранения информации – числовые данные в символьном виде
доступны на любом компьютере, при необходимости их может прочитать и
человек. Однако это преимущество имеет и обратную сторону медали –
преобразование числовых данных из машинных форматов в символьный вид
при выводе и обратное преобразование при вводе сопряжено с
Текстовый файл может быть создан путем записи на диск символьных
и/или числовых данных по заданному формату с помощью оператора fprintf. В качестве признака конца строки здесь заносятся те же самые
байты 0D0A, которые появляются на диске в результате вывода
управляющего символа \n.
Для инициализации текстового файла необходимо завести указатель на
структуру типа FILE и открыть файл по оператору в одном из
нужных режимов – "rt" (текстовый для чтения), "wt" (текстовый для
записи), "at" (текстовый для дозаписи в уже существующий набор
данных):
FILE *f1; ......... f1=fopen(имя_файла, "режим");
Формат оператора обмена с текстовыми файлами мало чем отличается от
операторов scanf ) и вывода ( printf ). Вместо них при
работе с файлами используются функции fscanf и fprintf, у которых
единственным дополнительным аргументом является указатель на
соответствующий файл:
fscanf(f1,"список_форматов", список_ввода); fprintf(f1,"список_форматов \n",список_вывода);
Если очередная строка текстового файла формируется из значения
элементов символьного массива str, то вместо функции fprintf проще
воспользоваться функцией fputs(f1, str). Чтение полной строки из
текстового файла удобнее выполнить с помощью функции fgets(str,n,f1).
Здесь параметр n означает максимальное количество считываемых
символов, если раньше не встретится управляющий байт 0A.
Библиотека C предусматривает и другие возможности для работы с
текстовыми файлами – функции open, create, read, write.
Пример 1. Рассмотрим программу, которая создает в текущем каталоге
(т.е. в каталоге, где находится наша программа) текстовый файл с
именем c_txt и записывает в него 10 строк. Каждая из записываемых
строк содержит символьное поле с текстом "Line" (5 байт, включая
нулевой байт – признак конца строки), пробел, поле целочисленного
значения переменной j, пробел и поле вещественного значения
квадратного корня из j. Очевидно, что числовые поля каждой строки
могут иметь разную длину. После записи информации файл закрывается и
вновь открывается, но уже для чтения. Для контроля содержимое
записываемых строк и содержимое считанных строк дублируется на
экране.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <conio.h>
main( )
{
FILE *f; //указатель на блок управления файлом
int j,k;
double d;
char s[]="Line";
f=fopen("c_txt","wt"); //создание нового или открытие существующего
// файла для записи
for(j=1;j<11;j++)
{
fprintf(f,"%s %d %lf\n",s,j,sqrt(j)); //запись в файл
printf("%s %d %lf\n",s,j,sqrt(j)); //вывод на экран
}
fclose(f); //закрытие файла
printf("\n");
f=fopen("c_txt","rt"); //открытие файла для чтения
for(j=10; j>0; j--)
{
fscanf(f,"%s %d %lf",s,k,d); //чтение из файла
printf("%s %d %lf\n",s,k,d); //вывод на экран
}
getch(); return 0;
}
//== Результат работы ===
Line 1 1.000000
Line 2 1.414214
Line 3 1.732051
Line 4 2.000000
Line 5 2.236068
Line 6 2.449490
Line 7 2.645751
Line 8 2.828427
Line 9 3.000000
Line 10 3.162278
Line 1 1.000000
Line 2 1.414214
Line 3 1.732051
Line 4 2.000000
Line 5 2.236068
Line 6 2.449490
Line 7 2.645751
Line 8 2.828427
Line 9 3.000000
Line 10 3.162278
Обратите внимание на возможную ошибку при наборе этой программы.
Если между форматными указателями %s и %d не сделать пробел, то в
файле текст "Line" склеится с последующим целым числом. После этого
при чтении в переменную s будут попадать строки вида "Line1", "Line2",
, "Line10", в переменную k будут считываться старшие цифры корня из j
(до символа "точка"), а в переменной d окажутся дробные разряды
соответствующего корня. Тогда результат работы программы будет
выглядеть следующим образом:
Line1 1.000000 Line2 1.414214 Line3 1.732051 Line4 2.000000 Line5 2.236068 Line6 2.449490 Line7 2.645751 Line8 2.828427 Line9 3.000000 Line10 3.162278 Line11 0.000000 Line21 0.414214 Line31 0.732051 Line42 0.000000 Line52 0.236068 Line62 0.449490 Line72 0.645751 Line82 0.828427 Line93 0.000000 Line103 0.162278
При считывании данных из текстового файла надо следить за
ситуацией, когда данные в файле исчерпаны. Для этой цели можно
воспользоваться функцией feof:
if(feof(f1))... //если данные исчерпаны
Двоичные файлы отличаются от текстовых тем, что представляют собой
последовательность байтов, содержимое которых может иметь различную
природу. Это могут быть байты, представляющие числовую информацию в
машинном формате, байты с графическими изображениями, байты с
аудиоинформацией и т.п. Содержимое таких байтов может случайно
совпасть с ASCII, но на них нельзя
реагировать так, как это делается при обработке текстовой информации.
Естественно, что единицей обмена с такими данными могут быть только
порции байтов указанной длины.
Создание двоичных файлов с помощью функции отличается от
создания текстовых файлов только указанием режима обмена – "rb"
(двоичный для чтения), "rb+" (двоичный для чтения и записи), "wb"
(двоичный для записи), "wb+" (двоичный для записи и чтения):
FILE *f1; ......... f1=fopen(имя_файла, "режим");
Обычно для обмена с двоичными файлами используются функции и fwrite:
c_w = fwrite(buf, size_rec, n_rec, f1);
Здесь
buf – указатель типа void* на начало буфера в оперативной памяти, из которого информация переписывается в файл;size_rec – размер передаваемой порции в байтах;n_rec – количество порций, которое должно быть записано в файл;f1 – указатель на блок управления файлом;c_w – количество порций, которое фактически записалось в файл.Считывание данных из двоичного файла осуществляется с помощью
функции с таким же набором параметров:
c_r = fread(buf, size_rec, n_rec, f1);
Здесь
c_r – количество порций, которое фактически прочиталось из файла;buf – указатель типа void* на начало буфера в оперативной памяти, в который информация считывается из файла.Обратите внимание на значения, возвращаемые функциями и fwrite. В какой ситуации количество записываемых порций может не
совпасть с количеством записавшихся данных? Как правило, на диске не
хватило места, и на такую ошибку надо реагировать. А вот при чтении
ситуация, когда количество прочитанных порций не совпадает с
количеством запрашиваемых порций, не обязательно является ошибкой.
Типичная картина – количество данных в файле не кратно размеру
заказанных порций.
Двоичные файлы допускают не только последовательный обмен данными.
Так как размеры порций данных и их количество, участвующее в очередном
обмене, диктуются программистом, а не смыслом информации, хранящейся в
файле, то имеется возможность пропустить часть данных или вернуться
повторно к ранее обработанной информации. Контроль за текущей позицией
доступных данных в файле осуществляет система с помощью указателя,
находящегося в блоке управления файлом. С помощью функции fseek
программист имеет возможность переместить этот указатель:
fseek(f1,delta,pos);
Здесь
f1 – указатель на блок управления файлом;delta – величина смещения в байтах, на которую следует переместить указатель файла;pos – позиция, от которой производится смещение указателя (0 или SEEK_SET – от начала файла, 1 или SEEK_CUR – от текущей позиции, 2 или SEEK_END – от конца файла)Кроме набора функций { } для работы с
двоичными файлами в библиотеке BC предусмотрены и другие средства – _dos_open /__dos_close, _dos_read /_dos_write, _create /_close, _read
/_write. Однако знакомство со всеми возможностями этой библиотеки в
рамках настоящего курса не предусмотрено.
Пример 2. Рассмотрим программу, которая создает двоичный файл для
записи с именем c_bin и записывает в него 4*10 порций данных в
машинном формате (строки, целые и вещественные числа). После записи
данных файл закрывается и вновь открывается для чтения. Для
демонстрации прямого доступа к данным информация из файла считывается
в обратном порядке – с конца. Контроль записываемой и считываемой
информации обеспечивается
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <conio.h>
main( )
{ FILE *f1; //указатель на блок управления файлом
int j,k;
char s[]="Line";
int n;
float r;
f1=fopen("c_bin","wb"); //создание двоичного файла для записи
for(j=1;j<11;j++)
{ r=sqrt(j);
fwrite(s,sizeof(s),1,f1); //запись строки в файл
fwrite(j,sizeof(int),1,f1); //запись целого числа в файл
fwrite(r,sizeof(float),1,f1); //запись вещественного числа
printf("\n%s %d %f",s,j,r); //контрольный вывод
}
fclose(f1); //закрытие файла
printf("\n");
f1=fopen("c_bin","rb"); //открытие двоичного файла для чтения
for(j=10; j>0; j--)
{//перемещение указателя файла
fseek(f1,(j-1)*(sizeof(s)+sizeof(int)+sizeof(float)),SEEK_SET);
fread(s,sizeof(s),1,f1); //чтение строки
fread(n,sizeof(int),1,f1); //чтение целого числа
fread(r,sizeof(float),1,f1); //чтение вещественного числа
printf("\n%s %d %f",s,n,r); //контрольный вывод
}
getch();
return 0;
}
//=== Результат работы ===
Line 1 1.000000
Line 2 1.414214
Line 3 1.732051
Line 4 2.000000
Line 5 2.236068
Line 6 2.449490
Line 7 2.645751
Line 8 2.828427
Line 9 3.000000
Line 10 3.162278
Line 10 3.162278
Line 9 3.000000
Line 8 2.828427
Line 7 2.645751
Line 6 2.449490
Line 5 2.236068
Line 4 2.000000
Line 3 1.732051
Line 2 1.414214
Line 1 1.000000
Использованные в этом примере операторы:
fclose(f1); //закрытие файла
f1=fopen("c_bin","rb"); //открытие двоичного файла для чтения
могут быть заменены обращением к единственной функции freopen, которая повторно открывает ранее открытый файл:
f1=freopen("c_bin","rb");
Основное правило, которого надо придерживаться при обмене с двоичными файлами звучит примерно так – как данные записывались в файл, так они должны и читаться.
Структурированный файл является частным случаем двоичного файла, в
котором в качестве порции обмена выступает структура языка C,
являющаяся точным аналогом записи в Паскале. По сравнению с предыдущим
примером использование записей позволяет сократить количество
, т.к. в одном обращении участвуют
все поля записи.
Инициализация структурированного файла выполняется точно таким же способом, как и подготовка к работе двоичного файла.
Пример 3. Приведенная ниже программа является модификацией
предыдущего примера. Единственное ее отличие состоит в использовании
структуры (записи) b, состоящей из символьного ( b.s, 5 байт, включая
нулевой байт – признак конца строки), целочисленного ( b.n, 2 байта в
BC и 4 байта в BCB) и вещественного ( b.r, 4 байта) полей.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <conio.h>
main( )
{ FILE *f1;
int j,k;
struct {
char s[5];
int n;
float r;
} b;
strcpy(b.s,"Line");
f1=fopen("c_rec","wb");
for(j=1;j<11;j++)
{ b.n=j; b.r=sqrt(j);
fwrite(b,sizeof(b),1,f1);
printf("\n%s %d %f",b.s,b.n,b.r);
}
fclose(f1);
printf("\n");
f1=fopen("c_rec","rb");
for(j=10; j>0; j--)
{ fseek(f1,(j-1)*sizeof(b),SEEK_SET);
fread(b,sizeof(b),1,f1);
printf("\n%s %d %f",b.s,b.n,b.r);
}
getch();
}
Результат работы этой программы ничем не отличается от предыдущего примера.
Библиотека языков C, C++ включает две функции sprintf и sscanf, с
помощью которых реализуются прямые и обратные форматные преобразования
данных в оперативной памяти. Техника их использования ничем не
отличается от уже рассмотренных функций printf/fprintf и scanf/fscanf.
Разница только в том, что первым аргументом новых функций является
указатель на строку – массив типа char, расположенный в оперативной
памяти. Для функции sscanf эта строка является источником данных, а
для функции sprintf в эту строку помещаются результаты преобразования
данных из машинного представления:
sscanf(str,"список_форматов", список_ввода); sprintf(str,"список_форматов \n",список_вывода);
К форматным преобразованиям в оперативной памяти можно прибегнуть и при работе с двоичным файлом. Перед записью в файл с помощью функции sprintf машинные форматы данных преобразуются в символьную строку, которая потом записывается в двоичный файл. По сути дела, такое же преобразование происходит при записи данных в текстовый файл.
Визуальная среда программирования BCB поддерживает все описанные
выше функции работы с файлами и предлагает дополнительный набор
средств ориентированных на возможности операционной системы Windows.
Главные отличия новых процедур заключаются в двух моментах. Во-первых,
вместо указателя на блок управления файлом здесь используется условный
целочисленный номер (мы будем обозначать его через fHandle ), который
операционная система присваивает каждому открываемому файлу (термин handle на американском сленге звучит как кликуха, кличка ). Во-вторых,
почти все строковые константы, используемые в качестве параметров
процедур, имеют тип AnsiString. Это новый тип (класс) строковых
данных, упрощающий манипуляции над строками. Чаще всего в
рассматриваемых ниже процедурах фигурирует строка с именем файла – FileName (на самом деле, в его качестве может выступать и полная
спецификация файла).
В некоторых ситуациях перед созданием нового файла или перед открытием существующего файла бывает полезно удостовериться в том, что файл с таким именем уже существует. В одном случае так можно предотвратить ошибочное уничтожение данных в существующем файле, который мы пытаемся открыть для записи. В другом случае так можно удостовериться в том, что файл, из которого мы собираемся читать исходные данные, действительно существует.
Для такого рода проверки используется функция FileExists:
if(FileExists(FileName))... //если файл существует
Под управлением MS-DOS аналогичную роль выполняла функция access:
k=access(имя_файла,0); //k=0,если файл существует
Для создания нового файла и его одновременного открытия
используется функция FileCreate:
int fHandle = FileCreate(FileName);
Если возвращаемое значение положительно, то работа по созданию
файла завершена успешно. В случае ошибки возвращаемое значение равно –1.
Для открытия существующего файла используется функция FileOpen:
int fHandle = FileOpen(FileName, Mode);
Здесь Mode – целочисленная константа, определяющая режим
работы файла. Список мнемонических констант, предусмотренных в системе
BCB, приведен в таблице 10.1.
| Константа | Режим |
|---|---|
fmOpenRead |
Файл открывается только для чтения |
fmOpenWrite |
Файл открывается только для записи |
fmOpenReadWrite |
Файл открывается и для записи, и для чтения |
fmShareExclusive |
Файл только для личного использования |
fmShareDenyWrite |
Файл доступен другим приложениям для чтения |
fmShareDenyRead |
Файл доступен другим приложениям для записи |
fmShareDenyNone |
Файл доступен всем и для чтения, и для записи |
Если значение, возвращаемое функцией равно -1, то открытие не
состоялось.
Для чтения двоичных данных из открытого файла используется функция FileRead:
int k = FileRead(fHandle, buf, count);
Здесь
buf – указатель типа void* на начало буфера, в который читаются данные;count – количество запрашиваемых байтов;k – количество реально прочитанных байтов.Для записи двоичных данных в открытый файл используется функция FileWrite:
k = FileWrite(fHandle, buf, count);
Здесь
buf – указатель типа void* на начало буфера, из которого пишутся данные;count – количество байтов, подлежащих записи;k – количество реально записанных байтов.Если k=-1, то произошла какая-то ошибка.
Указатель файла перемещают в нужную позицию для организации прямого
доступа к нужным данным. Для этой цели используется функция FileSeek:
int k = FileSeek(fHandle, delta, pos);
Здесь
delta – смещение в байтах, на которое нужно переместить указатель файла;pos – точка отсчета, относительно которой производится смещение (0 – от начала файла, 1 – от текущей позиции, 2 – от конца файла);k – новая текущая позиция.Для определения длины файла можно воспользоваться обращением:
fLength = FileSeek(fHandle,0,2);
Под управлением MS-DOS перемещение указателя в двоичном файле
выполняла функция fseek:
fseek(f1,delta,pos); //f1 – указатель типа FILE
Для закрытия файла используется функция FileClose:
FileClose(fHandle);
Описываемые ниже функции позволяют выделить из полной спецификации
файла имя диска, имя каталога, имя файла, расширение файла и путь к
файлу. Все они возвращают значение строки типа AnsiString:
s=ExtractFileDrive(FileName); //имя диска s=ExtractFileDir(FileName); //имя каталога s=ExtractFileName(FileName); //имя файла s=ExtractFileExt(FileName); //расширение имени файла s=ExtractFilePath(FileName); //путь к файлу
Аналогичные операции под управлением MS-DOS выполнялись
единственной функцией fnsplit, которая из полной спецификации файла
(первый аргумент функции) выделяла все составляющие компоненты:
fnsplit(const char *path,char *drive,char *dir,char *name,char *ext);
Функции удаления возвращают логическое значение true, если удаление
состоялось, и false в случае отказа от операции (например, нельзя
удалять не пустые каталоги, файлы с атрибутом Read-Only или
несуществующие файлы).
bv = DeleteFile(FileName); bv = RemoveDir(DirName);
Под управлением MS-DOS для удаления файла можно было
воспользоваться функцией unlink:
k=unlink(const char *filename); //k=0, если файл удален
Новый каталог создается с помощью функции CreateDir:
bv = CreateDir(DirName);
Если каталог создан, то возвращаемое значение равно true.
Для замены имени файла используется функция RenameFile:
bv = FileRename(OldName,NewName);
Если переименование состоялось, то возвращаемое значение равно true.
Новое расширение ( Extension ) заменяет прежнее расширение в имени
файла, если обратиться к функции ChangeExt:
as = ChangeFileExt(FileName, Extension);
При этом прежний файл и его содержимое сохраняется со своим старым
именем. Создается новое имя файла ( as ), имеющее новое расширение.
Точно такой же функции в системе MS-DOS нет, но там можно было бы
разложить спецификацию файла на составляющие (функция fnsplit ) и
заново собрать компоненты, подменив расширение файла (функция fnmerge ).
Функция FileGetAttr позволяет узнать
int k = FileGetAttr(FileName);
В таблице 10.2 приведены значения отдельных флажков.
| Флажок | Значение | Пояснение |
|---|---|---|
faReadOnly |
0x01 |
признак "Только для чтения" |
faHidden |
0x02 |
|
faSysFile |
0x04 |
системный файл |
faVolumeId |
0x08 |
признак "Идентификатор тома" |
faDirectory |
0x10 |
признак "Каталог" |
faArchive |
0x20 |
архивируемый файл |
faAnyFile |
0x3F |
суммарный набор признаков |
Для проверки того или иного признака можно воспользоваться указанными константами:
if(k faHidden)... //если файл скрытый
Для установки новых атрибутов используется функция FileSetAttr:
k = FileSetAttr(FileName,Attr);
Второй аргумент задается как логическая сумма флажков, приведенных в табл. 10.2:
Attr = faReadOnly | faSysFile;
Текущий каталог – это каталог, из которого запущена программа. Если файлы используемые программой находятся в текущем каталоге, то во всех файловых процедурах можно указывать только короткое имя файла. Если файл находится в другом каталоге, то приходится задавать полную спецификацию файла. Для сокращения можно изменить имя текущего каталога, чтобы избежать задания полных путей. Система BCB предлагает две функции, с помощью которых можно узнать или изменить имя текущего каталога:
as = GetCurrentDir(); //опрос имени текущего каталога vb = SetCurrentDir(NameDir); //смена текущего каталога
Одной из довольно распространенных процедур является составление
списка файлов указанного каталога, имена которых удовлетворяют
заданной маске. Под управлением MS-DOS такая задача решается с помощью
функций (найти первый файл) и (найти следующий
файл). Обе функции используют в качестве одного из своих аргументов
адрес структуры типа ffblk, в которую они заносят информацию о
найденном файле:
struct ffblk {
char ff_reserved[21]; //зарезервировано для MS-DOS
char ff_attrib; //байт атрибутов найденного файла
int ff_time; //время создания/модификации файла
int ff_date; //дата создания/модификации файла
long ff_size; //размер файла
char ff_name[13]; //имя найденного файла
};
Описание этой структуры и прототипы указанных функций находятся в
заголовочном файле dir.h. Обе функции возвращают нулевое значение,
если поиск закончился удачно. Достаточно четкое представление об их
использовании дает следующий пример, который выводит на экран список
всех файлов с расширением .cpp из каталога c:\bc\bin:
#include <stdio.h>
#include <conio.h>
#include <dir.h>
void main()
{ struct ffblk qq;
int a;
printf("Список файлов *.cpp\n");
a=findfirst("c:\\bc\\bin\\*.cpp",qq,0); //поиск первого файла
while(!a)
{ printf(" %s\n",qq.ff_name);
a=findnext(qq); //поиск следующего файла
}
getch();
}
Первый аргумент функции определяет маску, которой должно
удовлетворять имя искомого файла. Третий аргумент этой функции имеет
тип int и позволяет фильтровать найденные объекты по любой комбинации
их атрибутов в файловой системе (Read Only, Hidden, System, Archive,
Volume, Directory). Нулевое значение этого параметра, использованное в
примере, игнорирует отбор по атрибутам.
Точно таким же способом можно осуществлять поиск нужных файлов в среде BCB.
В большинстве своем файлы представляют собой
К числу абонентов, которые могут участвовать в обмене данными,
относятся и файлы-устройства (дисплей, принтер,
Файловая подсистема рассматривает
Кластер – это несколько следующих друг за другом секторов дискового
пространства (по умолчанию объем каждого физического сектора – 512
байт).
Кроме информации о файлах в корневом каталоге содержатся сведения о
вложенных подкаталогах, устроенных по тому же принципу, что и корневой
каталог.

При использовании имен файлов в программах на языках C, C++ следует помнить об одном соглашении – спецификация файла задается строкой, в которой знак "обратного слэша" заменяется удвоенным обратным слэшем:
char namef[]="c:\\bc\\bin\\bc.exe"
Файловая подсистема обеспечивает возможность создания новых
подкаталогов, создания и удаления файлов, копирования и переименования
файлов. Средства операционной системы обеспечивают некоторую защиту
наборов данных – например, системные и
Оценивая ключевые аспекты процесса обмена данными, можно сказать, что работа с файлами, в основном, ограничивается тремя-четырьмя операциями:
Несмотря на кажущуюся простоту процесса обмена данными, файловые операции достаточно сложны в освоении. Во-первых, не следует забывать о трех уровнях доступа к файловым данным (BIOS, операционная система, система программирования). Во-вторых, операционные системы MS-DOS, Windows и Linux пытаются достичь совместимости в выполнении файловых операций. Все это приводит к появлению довольно большого количества различных обслуживающих программ. Так, системная библиотека BC 3.1 насчитывает более 120 функций для работы с файлами и свыше 60 констант, задающих режимы работы файловых процедур.
При работе с файлами приходится учитывать многочисленные форматы
представления данных того или иного типа на разных носителях
информации. Так, например, цепочка из k символов, представляющая
текстовую строку, может храниться в одном из следующих форматов:
"S1S2S3...Sk" (переменное число символов, заключенных в одинарные или двойные кавычки);kS1S2...Sk ( k – однобайтовый или двухбайтовый счетчик числа символов, предшествующий тексту);S1S2...Sk\0 ( \0 – однобайтовый признак конца строки, расположенный вслед за последним символом текста);S1S2...Sk 0D 0A (двухбайтовый признак конца строки, 0D –"возврат каретки", 0A – "перевод строки").Числовая информация может быть записана в дисковый файл либо в машинном формате (а в языках С, С++ количество разных типов числовых данных достигает десятка), либо с предварительным преобразованием из машинного представления в символьное.
Кроме числовых и текстовых данных в файлах может храниться
информация и другого происхождения. Например, графические изображения,
которые в процессах обмена данными выступают как двоичные коды,
условно разделенные на байты. Естественно, что на содержимое этих
байтов нельзя реагировать так же, как на некоторые
Далее, существует несколько способов доступа к файловым данным, из
которых на практике чаще всего используют два – последовательный и произвольный. Последний иногда называют прямым ( ) или случайным ( ).
Последовательный доступ при записи на диск характерен тем, что очередная записываемая порция пристраивается в хвост к предыдущей. Размеры смежных порций при этом могут оказаться разными по длине. При чтении такой набор данных начинает извлекаться с самой первой порции и очередность считываемых данных повторяет их последовательность во время записи.
Файлы с произвольным доступом состоят из данных, разбитых на порции фиксированной длины. При этом имеется возможность записывать или читать данные в произвольном порядке, указывая дополнительно номер нужной порции.
Наконец, необходимо учитывать и способы разделения отдельных числовых или символьных значений в дисковых наборах данных. В некоторых ситуациях роль таких разграничителей могут выполнять кавычки, запятые, пробелы и различные управляющие байты ( "табуляторный пропуск", "возврат каретки", "перевод строки", "признак конца файла" ). В других ситуациях для каждого данного может быть выделено поле фиксированной длины.
Системы программирования BC 3.1 и BCB поддерживает работу с файлами и потоками, данные в которых представлены либо в символьном, либо в двоичном формате.
Содержимое текстового файла очень напоминает то, что мы видим на экране дисплея, когда программа отображает на нем результаты вычислений. Разница только в том, что на экран дисплея только выводят, а текстовый файл можно использовать как хранилище информации, в которое не только пишут, но из которого еще и читают.
Текстовые файлы относятся к файлам последовательного доступа, т.к.
единицей хранения информации в них являются строки переменной длины.
Каждая строка заканчивается специальным признаком, обычно его функцию
выполняет пара символов 0D0A – "возврат каретки" и "перевод строки".
Самым важным преимуществом текстовых файлов является универсальность
формата хранения информации – числовые данные в символьном виде
доступны на любом компьютере, при необходимости их может прочитать и
человек. Однако это преимущество имеет и обратную сторону медали –
преобразование числовых данных из машинных форматов в символьный вид
при выводе и обратное преобразование при вводе сопряжено с
Текстовый файл может быть создан путем записи на диск символьных
и/или числовых данных по заданному формату с помощью оператора fprintf. В качестве признака конца строки здесь заносятся те же самые
байты 0D0A, которые появляются на диске в результате вывода
управляющего символа \n.
Для инициализации текстового файла необходимо завести указатель на
структуру типа FILE и открыть файл по оператору в одном из
нужных режимов – "rt" (текстовый для чтения), "wt" (текстовый для
записи), "at" (текстовый для дозаписи в уже существующий набор
данных):
FILE *f1; ......... f1=fopen(имя_файла, "режим");
Формат оператора обмена с текстовыми файлами мало чем отличается от
операторов scanf ) и вывода ( printf ). Вместо них при
работе с файлами используются функции fscanf и fprintf, у которых
единственным дополнительным аргументом является указатель на
соответствующий файл:
fscanf(f1,"список_форматов", список_ввода); fprintf(f1,"список_форматов \n",список_вывода);
Если очередная строка текстового файла формируется из значения
элементов символьного массива str, то вместо функции fprintf проще
воспользоваться функцией fputs(f1, str). Чтение полной строки из
текстового файла удобнее выполнить с помощью функции fgets(str,n,f1).
Здесь параметр n означает максимальное количество считываемых
символов, если раньше не встретится управляющий байт 0A.
Библиотека C предусматривает и другие возможности для работы с
текстовыми файлами – функции open, create, read, write.
Пример 1. Рассмотрим программу, которая создает в текущем каталоге
(т.е. в каталоге, где находится наша программа) текстовый файл с
именем c_txt и записывает в него 10 строк. Каждая из записываемых
строк содержит символьное поле с текстом "Line" (5 байт, включая
нулевой байт – признак конца строки), пробел, поле целочисленного
значения переменной j, пробел и поле вещественного значения
квадратного корня из j. Очевидно, что числовые поля каждой строки
могут иметь разную длину. После записи информации файл закрывается и
вновь открывается, но уже для чтения. Для контроля содержимое
записываемых строк и содержимое считанных строк дублируется на
экране.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <conio.h>
main( )
{
FILE *f; //указатель на блок управления файлом
int j,k;
double d;
char s[]="Line";
f=fopen("c_txt","wt"); //создание нового или открытие существующего
// файла для записи
for(j=1;j<11;j++)
{
fprintf(f,"%s %d %lf\n",s,j,sqrt(j)); //запись в файл
printf("%s %d %lf\n",s,j,sqrt(j)); //вывод на экран
}
fclose(f); //закрытие файла
printf("\n");
f=fopen("c_txt","rt"); //открытие файла для чтения
for(j=10; j>0; j--)
{
fscanf(f,"%s %d %lf",s,k,d); //чтение из файла
printf("%s %d %lf\n",s,k,d); //вывод на экран
}
getch(); return 0;
}
//== Результат работы ===
Line 1 1.000000
Line 2 1.414214
Line 3 1.732051
Line 4 2.000000
Line 5 2.236068
Line 6 2.449490
Line 7 2.645751
Line 8 2.828427
Line 9 3.000000
Line 10 3.162278
Line 1 1.000000
Line 2 1.414214
Line 3 1.732051
Line 4 2.000000
Line 5 2.236068
Line 6 2.449490
Line 7 2.645751
Line 8 2.828427
Line 9 3.000000
Line 10 3.162278
Обратите внимание на возможную ошибку при наборе этой программы.
Если между форматными указателями %s и %d не сделать пробел, то в
файле текст "Line" склеится с последующим целым числом. После этого
при чтении в переменную s будут попадать строки вида "Line1", "Line2",
, "Line10", в переменную k будут считываться старшие цифры корня из j
(до символа "точка"), а в переменной d окажутся дробные разряды
соответствующего корня. Тогда результат работы программы будет
выглядеть следующим образом:
Line1 1.000000 Line2 1.414214 Line3 1.732051 Line4 2.000000 Line5 2.236068 Line6 2.449490 Line7 2.645751 Line8 2.828427 Line9 3.000000 Line10 3.162278 Line11 0.000000 Line21 0.414214 Line31 0.732051 Line42 0.000000 Line52 0.236068 Line62 0.449490 Line72 0.645751 Line82 0.828427 Line93 0.000000 Line103 0.162278
При считывании данных из текстового файла надо следить за
ситуацией, когда данные в файле исчерпаны. Для этой цели можно
воспользоваться функцией feof:
if(feof(f1))... //если данные исчерпаны
Двоичные файлы отличаются от текстовых тем, что представляют собой
последовательность байтов, содержимое которых может иметь различную
природу. Это могут быть байты, представляющие числовую информацию в
машинном формате, байты с графическими изображениями, байты с
аудиоинформацией и т.п. Содержимое таких байтов может случайно
совпасть с ASCII, но на них нельзя
реагировать так, как это делается при обработке текстовой информации.
Естественно, что единицей обмена с такими данными могут быть только
порции байтов указанной длины.
Создание двоичных файлов с помощью функции отличается от
создания текстовых файлов только указанием режима обмена – "rb"
(двоичный для чтения), "rb+" (двоичный для чтения и записи), "wb"
(двоичный для записи), "wb+" (двоичный для записи и чтения):
FILE *f1; ......... f1=fopen(имя_файла, "режим");
Обычно для обмена с двоичными файлами используются функции и fwrite:
c_w = fwrite(buf, size_rec, n_rec, f1);
Здесь
buf – указатель типа void* на начало буфера в оперативной памяти, из которого информация переписывается в файл;size_rec – размер передаваемой порции в байтах;n_rec – количество порций, которое должно быть записано в файл;f1 – указатель на блок управления файлом;c_w – количество порций, которое фактически записалось в файл.Считывание данных из двоичного файла осуществляется с помощью
функции с таким же набором параметров:
c_r = fread(buf, size_rec, n_rec, f1);
Здесь
c_r – количество порций, которое фактически прочиталось из файла;buf – указатель типа void* на начало буфера в оперативной памяти, в который информация считывается из файла.Обратите внимание на значения, возвращаемые функциями и fwrite. В какой ситуации количество записываемых порций может не
совпасть с количеством записавшихся данных? Как правило, на диске не
хватило места, и на такую ошибку надо реагировать. А вот при чтении
ситуация, когда количество прочитанных порций не совпадает с
количеством запрашиваемых порций, не обязательно является ошибкой.
Типичная картина – количество данных в файле не кратно размеру
заказанных порций.
Двоичные файлы допускают не только последовательный обмен данными.
Так как размеры порций данных и их количество, участвующее в очередном
обмене, диктуются программистом, а не смыслом информации, хранящейся в
файле, то имеется возможность пропустить часть данных или вернуться
повторно к ранее обработанной информации. Контроль за текущей позицией
доступных данных в файле осуществляет система с помощью указателя,
находящегося в блоке управления файлом. С помощью функции fseek
программист имеет возможность переместить этот указатель:
fseek(f1,delta,pos);
Здесь
f1 – указатель на блок управления файлом;delta – величина смещения в байтах, на которую следует переместить указатель файла;pos – позиция, от которой производится смещение указателя (0 или SEEK_SET – от начала файла, 1 или SEEK_CUR – от текущей позиции, 2 или SEEK_END – от конца файла)Кроме набора функций { } для работы с
двоичными файлами в библиотеке BC предусмотрены и другие средства – _dos_open /__dos_close, _dos_read /_dos_write, _create /_close, _read
/_write. Однако знакомство со всеми возможностями этой библиотеки в
рамках настоящего курса не предусмотрено.
Пример 2. Рассмотрим программу, которая создает двоичный файл для
записи с именем c_bin и записывает в него 4*10 порций данных в
машинном формате (строки, целые и вещественные числа). После записи
данных файл закрывается и вновь открывается для чтения. Для
демонстрации прямого доступа к данным информация из файла считывается
в обратном порядке – с конца. Контроль записываемой и считываемой
информации обеспечивается
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <conio.h>
main( )
{ FILE *f1; //указатель на блок управления файлом
int j,k;
char s[]="Line";
int n;
float r;
f1=fopen("c_bin","wb"); //создание двоичного файла для записи
for(j=1;j<11;j++)
{ r=sqrt(j);
fwrite(s,sizeof(s),1,f1); //запись строки в файл
fwrite(j,sizeof(int),1,f1); //запись целого числа в файл
fwrite(r,sizeof(float),1,f1); //запись вещественного числа
printf("\n%s %d %f",s,j,r); //контрольный вывод
}
fclose(f1); //закрытие файла
printf("\n");
f1=fopen("c_bin","rb"); //открытие двоичного файла для чтения
for(j=10; j>0; j--)
{//перемещение указателя файла
fseek(f1,(j-1)*(sizeof(s)+sizeof(int)+sizeof(float)),SEEK_SET);
fread(s,sizeof(s),1,f1); //чтение строки
fread(n,sizeof(int),1,f1); //чтение целого числа
fread(r,sizeof(float),1,f1); //чтение вещественного числа
printf("\n%s %d %f",s,n,r); //контрольный вывод
}
getch();
return 0;
}
//=== Результат работы ===
Line 1 1.000000
Line 2 1.414214
Line 3 1.732051
Line 4 2.000000
Line 5 2.236068
Line 6 2.449490
Line 7 2.645751
Line 8 2.828427
Line 9 3.000000
Line 10 3.162278
Line 10 3.162278
Line 9 3.000000
Line 8 2.828427
Line 7 2.645751
Line 6 2.449490
Line 5 2.236068
Line 4 2.000000
Line 3 1.732051
Line 2 1.414214
Line 1 1.000000
Использованные в этом примере операторы:
fclose(f1); //закрытие файла
f1=fopen("c_bin","rb"); //открытие двоичного файла для чтения
могут быть заменены обращением к единственной функции freopen, которая повторно открывает ранее открытый файл:
f1=freopen("c_bin","rb");
Основное правило, которого надо придерживаться при обмене с двоичными файлами звучит примерно так – как данные записывались в файл, так они должны и читаться.
Структурированный файл является частным случаем двоичного файла, в
котором в качестве порции обмена выступает структура языка C,
являющаяся точным аналогом записи в Паскале. По сравнению с предыдущим
примером использование записей позволяет сократить количество
, т.к. в одном обращении участвуют
все поля записи.
Инициализация структурированного файла выполняется точно таким же способом, как и подготовка к работе двоичного файла.
Пример 3. Приведенная ниже программа является модификацией
предыдущего примера. Единственное ее отличие состоит в использовании
структуры (записи) b, состоящей из символьного ( b.s, 5 байт, включая
нулевой байт – признак конца строки), целочисленного ( b.n, 2 байта в
BC и 4 байта в BCB) и вещественного ( b.r, 4 байта) полей.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <conio.h>
main( )
{ FILE *f1;
int j,k;
struct {
char s[5];
int n;
float r;
} b;
strcpy(b.s,"Line");
f1=fopen("c_rec","wb");
for(j=1;j<11;j++)
{ b.n=j; b.r=sqrt(j);
fwrite(b,sizeof(b),1,f1);
printf("\n%s %d %f",b.s,b.n,b.r);
}
fclose(f1);
printf("\n");
f1=fopen("c_rec","rb");
for(j=10; j>0; j--)
{ fseek(f1,(j-1)*sizeof(b),SEEK_SET);
fread(b,sizeof(b),1,f1);
printf("\n%s %d %f",b.s,b.n,b.r);
}
getch();
}
Результат работы этой программы ничем не отличается от предыдущего примера.
Библиотека языков C, C++ включает две функции sprintf и sscanf, с
помощью которых реализуются прямые и обратные форматные преобразования
данных в оперативной памяти. Техника их использования ничем не
отличается от уже рассмотренных функций printf/fprintf и scanf/fscanf.
Разница только в том, что первым аргументом новых функций является
указатель на строку – массив типа char, расположенный в оперативной
памяти. Для функции sscanf эта строка является источником данных, а
для функции sprintf в эту строку помещаются результаты преобразования
данных из машинного представления:
sscanf(str,"список_форматов", список_ввода); sprintf(str,"список_форматов \n",список_вывода);
К форматным преобразованиям в оперативной памяти можно прибегнуть и при работе с двоичным файлом. Перед записью в файл с помощью функции sprintf машинные форматы данных преобразуются в символьную строку, которая потом записывается в двоичный файл. По сути дела, такое же преобразование происходит при записи данных в текстовый файл.
Визуальная среда программирования BCB поддерживает все описанные
выше функции работы с файлами и предлагает дополнительный набор
средств ориентированных на возможности операционной системы Windows.
Главные отличия новых процедур заключаются в двух моментах. Во-первых,
вместо указателя на блок управления файлом здесь используется условный
целочисленный номер (мы будем обозначать его через fHandle ), который
операционная система присваивает каждому открываемому файлу (термин handle на американском сленге звучит как кликуха, кличка ). Во-вторых,
почти все строковые константы, используемые в качестве параметров
процедур, имеют тип AnsiString. Это новый тип (класс) строковых
данных, упрощающий манипуляции над строками. Чаще всего в
рассматриваемых ниже процедурах фигурирует строка с именем файла – FileName (на самом деле, в его качестве может выступать и полная
спецификация файла).
В некоторых ситуациях перед созданием нового файла или перед открытием существующего файла бывает полезно удостовериться в том, что файл с таким именем уже существует. В одном случае так можно предотвратить ошибочное уничтожение данных в существующем файле, который мы пытаемся открыть для записи. В другом случае так можно удостовериться в том, что файл, из которого мы собираемся читать исходные данные, действительно существует.
Для такого рода проверки используется функция FileExists:
if(FileExists(FileName))... //если файл существует
Под управлением MS-DOS аналогичную роль выполняла функция access:
k=access(имя_файла,0); //k=0,если файл существует
Для создания нового файла и его одновременного открытия
используется функция FileCreate:
int fHandle = FileCreate(FileName);
Если возвращаемое значение положительно, то работа по созданию
файла завершена успешно. В случае ошибки возвращаемое значение равно –1.
Для открытия существующего файла используется функция FileOpen:
int fHandle = FileOpen(FileName, Mode);
Здесь Mode – целочисленная константа, определяющая режим
работы файла. Список мнемонических констант, предусмотренных в системе
BCB, приведен в таблице 10.1.
| Константа | Режим |
|---|---|
fmOpenRead |
Файл открывается только для чтения |
fmOpenWrite |
Файл открывается только для записи |
fmOpenReadWrite |
Файл открывается и для записи, и для чтения |
fmShareExclusive |
Файл только для личного использования |
fmShareDenyWrite |
Файл доступен другим приложениям для чтения |
fmShareDenyRead |
Файл доступен другим приложениям для записи |
fmShareDenyNone |
Файл доступен всем и для чтения, и для записи |
Если значение, возвращаемое функцией равно -1, то открытие не
состоялось.
Для чтения двоичных данных из открытого файла используется функция FileRead:
int k = FileRead(fHandle, buf, count);
Здесь
buf – указатель типа void* на начало буфера, в который читаются данные;count – количество запрашиваемых байтов;k – количество реально прочитанных байтов.Для записи двоичных данных в открытый файл используется функция FileWrite:
k = FileWrite(fHandle, buf, count);
Здесь
buf – указатель типа void* на начало буфера, из которого пишутся данные;count – количество байтов, подлежащих записи;k – количество реально записанных байтов.Если k=-1, то произошла какая-то ошибка.
Указатель файла перемещают в нужную позицию для организации прямого
доступа к нужным данным. Для этой цели используется функция FileSeek:
int k = FileSeek(fHandle, delta, pos);
Здесь
delta – смещение в байтах, на которое нужно переместить указатель файла;pos – точка отсчета, относительно которой производится смещение (0 – от начала файла, 1 – от текущей позиции, 2 – от конца файла);k – новая текущая позиция.Для определения длины файла можно воспользоваться обращением:
fLength = FileSeek(fHandle,0,2);
Под управлением MS-DOS перемещение указателя в двоичном файле
выполняла функция fseek:
fseek(f1,delta,pos); //f1 – указатель типа FILE
Для закрытия файла используется функция FileClose:
FileClose(fHandle);
Описываемые ниже функции позволяют выделить из полной спецификации
файла имя диска, имя каталога, имя файла, расширение файла и путь к
файлу. Все они возвращают значение строки типа AnsiString:
s=ExtractFileDrive(FileName); //имя диска s=ExtractFileDir(FileName); //имя каталога s=ExtractFileName(FileName); //имя файла s=ExtractFileExt(FileName); //расширение имени файла s=ExtractFilePath(FileName); //путь к файлу
Аналогичные операции под управлением MS-DOS выполнялись
единственной функцией fnsplit, которая из полной спецификации файла
(первый аргумент функции) выделяла все составляющие компоненты:
fnsplit(const char *path,char *drive,char *dir,char *name,char *ext);
Функции удаления возвращают логическое значение true, если удаление
состоялось, и false в случае отказа от операции (например, нельзя
удалять не пустые каталоги, файлы с атрибутом Read-Only или
несуществующие файлы).
bv = DeleteFile(FileName); bv = RemoveDir(DirName);
Под управлением MS-DOS для удаления файла можно было
воспользоваться функцией unlink:
k=unlink(const char *filename); //k=0, если файл удален
Новый каталог создается с помощью функции CreateDir:
bv = CreateDir(DirName);
Если каталог создан, то возвращаемое значение равно true.
Для замены имени файла используется функция RenameFile:
bv = FileRename(OldName,NewName);
Если переименование состоялось, то возвращаемое значение равно true.
Новое расширение ( Extension ) заменяет прежнее расширение в имени
файла, если обратиться к функции ChangeExt:
as = ChangeFileExt(FileName, Extension);
При этом прежний файл и его содержимое сохраняется со своим старым
именем. Создается новое имя файла ( as ), имеющее новое расширение.
Точно такой же функции в системе MS-DOS нет, но там можно было бы
разложить спецификацию файла на составляющие (функция fnsplit ) и
заново собрать компоненты, подменив расширение файла (функция fnmerge ).
Функция FileGetAttr позволяет узнать
int k = FileGetAttr(FileName);
В таблице 10.2 приведены значения отдельных флажков.
| Флажок | Значение | Пояснение |
|---|---|---|
faReadOnly |
0x01 |
признак "Только для чтения" |
faHidden |
0x02 |
|
faSysFile |
0x04 |
системный файл |
faVolumeId |
0x08 |
признак "Идентификатор тома" |
faDirectory |
0x10 |
признак "Каталог" |
faArchive |
0x20 |
архивируемый файл |
faAnyFile |
0x3F |
суммарный набор признаков |
Для проверки того или иного признака можно воспользоваться указанными константами:
if(k faHidden)... //если файл скрытый
Для установки новых атрибутов используется функция FileSetAttr:
k = FileSetAttr(FileName,Attr);
Второй аргумент задается как логическая сумма флажков, приведенных в табл. 10.2:
Attr = faReadOnly | faSysFile;
Текущий каталог – это каталог, из которого запущена программа. Если файлы используемые программой находятся в текущем каталоге, то во всех файловых процедурах можно указывать только короткое имя файла. Если файл находится в другом каталоге, то приходится задавать полную спецификацию файла. Для сокращения можно изменить имя текущего каталога, чтобы избежать задания полных путей. Система BCB предлагает две функции, с помощью которых можно узнать или изменить имя текущего каталога:
as = GetCurrentDir(); //опрос имени текущего каталога vb = SetCurrentDir(NameDir); //смена текущего каталога
Одной из довольно распространенных процедур является составление
списка файлов указанного каталога, имена которых удовлетворяют
заданной маске. Под управлением MS-DOS такая задача решается с помощью
функций (найти первый файл) и (найти следующий
файл). Обе функции используют в качестве одного из своих аргументов
адрес структуры типа ffblk, в которую они заносят информацию о
найденном файле:
struct ffblk {
char ff_reserved[21]; //зарезервировано для MS-DOS
char ff_attrib; //байт атрибутов найденного файла
int ff_time; //время создания/модификации файла
int ff_date; //дата создания/модификации файла
long ff_size; //размер файла
char ff_name[13]; //имя найденного файла
};
Описание этой структуры и прототипы указанных функций находятся в
заголовочном файле dir.h. Обе функции возвращают нулевое значение,
если поиск закончился удачно. Достаточно четкое представление об их
использовании дает следующий пример, который выводит на экран список
всех файлов с расширением .cpp из каталога c:\bc\bin:
#include <stdio.h>
#include <conio.h>
#include <dir.h>
void main()
{ struct ffblk qq;
int a;
printf("Список файлов *.cpp\n");
a=findfirst("c:\\bc\\bin\\*.cpp",qq,0); //поиск первого файла
while(!a)
{ printf(" %s\n",qq.ff_name);
a=findnext(qq); //поиск следующего файла
}
getch();
}
Первый аргумент функции определяет маску, которой должно
удовлетворять имя искомого файла. Третий аргумент этой функции имеет
тип int и позволяет фильтровать найденные объекты по любой комбинации
их атрибутов в файловой системе (Read Only, Hidden, System, Archive,
Volume, Directory). Нулевое значение этого параметра, использованное в
примере, игнорирует отбор по атрибутам.
Точно таким же способом можно осуществлять поиск нужных файлов в среде BCB.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.