КАК работать с файлами?


КАК мне поможет знание о файлах?
КАК создать файл, не используя "Проводник"?
КАК записать в файл текст, который я хочу?
КАК прочитать из файла текст, который я в него записал?
КАК создать папку без кнопки F7?
КАК удалить папку с надоевшей игрой?
КАК можно узнать атрибуты файла?
КАК прочитать дерево файлов?



Вопрос: КАК мне поможет знание о файлах?

Файлы... Куда же без них? Картинки и песни, вэб-странички и текстовые документы, электронные таблицы Excel, видеофильмы, базы данных - всё это файлы. До сих пор, чтобы создать файл, вы пользовались программами типа "Проводник", Far или Windows Commander. Пришло время взять управление компьютером в свои руки!
В системе Windows постоянно происходят тысячи файловых операций - создаются новые файлы, удаляются старые, ведётся запись и чтение файловой информации. Но все эти операции скрыты от пользователя, и как правило, мы об этом ничего не знаем.
Наша задача - научить нашу программу работать с файлами так же уверенно, чтобы пользователь ровным счётом ни о чём не догадывался, что сделало бы его работу комфортной, а работу программы стабильной.
Файлы часто выручают нас в трудную минуту. Предствьте себе инженера-математика, который дома расчитывает такую сложную систему, что даже самый современный компьютер не в состоянии сделать это быстро. Получая всё новые и новые данные, компьютер выполняет миллионы математических операций. На это уходит несколько дней, а может и недель. В один прекрасный день, в доме у математика отключают свет - это кстати вполне рядовой случай. И что тогда - прощай все вычисления? Если математик был мудр, он предусмотрел в своей программе своевременную запись в файл всех промежуточных результатов. Даже если компьютер выключить из розетки, в файле сохранится ценная информация, и вычисления можно будет продолжить с того же места, где процесс остановился. Согласитесь, это очень удобно!
Итак, без файлов наша жизнь немыслима. И сегодня мы снова почувствуем себя творцами, на этот раз обуздав файлы!


Вопрос: КАК создать файл, не используя "Проводник"?

Начнём с самого простого - создадим файл в корневом каталоге диска С. Программа запустится совсем ненадолго, но после её завершения вы найдёте на диске С новый файл privet.txt.

#include <stdio.h>
#include<dir.h>

void main()
{
chdir("c:\\ "); //переходим на диск С:
FILE *f=fopen("privet.txt", "w"); //объявляем файловую переменную типа FILE.
fclose(f); //закрываем файл

}

Здесь мы впервые используем библиотеку dir.h. Это библиотека незаменима при работе с файлами и папками. В ней содержится всё множество функций для работы с каталогами. Кроме того, она удобна для поиска файлов и построения небольших файловых менеджеров.

Для того, чтобы создать файл в корневом каталоге используем функцию chdir ("change directory"). В один момент времени текущей может быть только одна папка. Когда вы запускаете программу, текущей для неё всегда является та папка, из которой она запускается. Поэтому если вы хотите создать файл в каком-то определённом каталоге, необходимо перейти в него.


chdir("c:\\");

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

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

Код
Режим
r
Открыть файл только для чтения без права записи
w
Открыть файл для записи. Если такой файл уже существует - перезаписать
a
Если файл существует, добавлять информацию в конец
r+
Открыть существующий файл для чтения и записи
w+
Создать файл для перезаписи
a+
Открыть для записи в конец. Если такого файла нет, создать его

Если нам необходимо только считать данные из файла, но ни в коем случае не менять его драгоценное содержимое, нам нужен ключ "r" ("read" - чтение). Если мы не уверены существует ли такой файл, и в случае если он не существует, мы хотим его создать, чтобы туда что-то записать, нам поможет ключ "w" ("write" - запись). Если подобно инженеру-математику, мы хотим дописывать в конец файла всё новые и новые данные - для нас ключ "a" ("append" - добавить). Существуют также комбинированные ключи, которые делают эту функцию ещё более гибкой. Так ключ "r+" откроет файл для чтения, но если файла нет, он его создаст. Ключ "w+" - расширение ключа "w" - перезапись файл. Если файл, в который мы хотим что-то дописать был удалён, функция fopen с ключом "a+" создаст его снова.

После того, как мы завершили все операции с файлом, его необходимо закрыть. Спешу вас сразу обрадовать - после завершения работы нашей программы, все файлы, которые в ней были открыты и не закрыты, закроются сами собой. Но это не большое облегчение. Ведь если мы захотим записать что-то в файл, который уже был открыт только для чтения, сделать нам это не удастся. И если мы захотим его переоткрыть для записи, из этого тоже ничего не выйдет. Признак хорошего стиля программирования - открывать файл только для совершения какой-то операции и после её выполнения сразу же закрывать его. Функции fopen/fclose должны использоваться только в паре, как открывающие и завершающие скобки { / }.

Вопрос: КАК записать в файл текст, который я хочу?

Усложняем предыдущую программу.

#include<stdio.h>
#include<dir.h>

void main()
{
chdir("c:\\");
FILE *f=fopen("privet.txt", "w"); //объявляем файловую переменную типа FILE

fprintf(f, "Hello, user!!!!");
fclose(f); //закрываем файл
}

Функция fprintf - работает аналогично функции printf, только в качестве потока вывода используется не экран, а файл. Идентификатор файловой переменной всегда должен быть первым аргументом. Конечно надо учесть, что для записи в файл, он должен быть открыт для не для чтения, а для записи или дозаписи.

Вопрос: КАК прочитать из файла текст, который я в него записал?

Иногда программы используют файлы для хранения каких-то данных уже после завершения работы программы. Например, пользователь выбрал в настройках, что всегда хочет использовать синие меню, а не серые, и необходимо, чтобы программа при следующем своём запуске загрузилась уже загрузилась с синим меню. Удобно хранить информацию о цвете меню в файле и при следующем запуске считать её.
Для чтения из файлов по аналогии с fprintf используется fscanf. Как входной поток она использует файл, а не клавиатуру.

#include<stdio.h>

void main()
{
FILE *f;
char *str;

//Если файл открыть нельзя
if((f=fopen("privet.txt", "rt"))==0)
printf("\nНевозможно открыть файл!"):

else{
fscanf(f, "%s", str);
printf("\nВ файле была записана строка: %s", str);
}

}

В системе Windows файловый ввод-вывод используется очень широко. Но хранения данных программы Windows-приложения используют не файлы, а системный реестр. Для каждой установленной программы в нём резервируется ячейка, как шкафчик в камере хранения, где программа может создавать какие угодно переменные и давать им какие угодно значения. Это удобно, так как работа программы не зависит от места, где она расположена, данные реестра сохраняются после завершения программы. И даже если удалить папку с программой, с данными ничего не случится. При следующей установке программы реестр всё также будет хранить эти данные и их не придётся восстанавливать.

Вопрос: КАК создать папку без кнопки F7?

Иногда необходимо программно создать папку, в которой, например, будут храниться настройки пользователя. Можно конечно попросить пользователя создать такую папку самому или указать уже существующую. А можно его и не беспокоить. В приведённом примере я научу вас не только создавать папку, но и определять текущий путь, чтобы потом в него вернуться. Ведь точка входа в программу и точка выхода всегда должны совпадать. Для определения нашего пути, мы создадим свою собственную функцию типа char * (строка), которая будет определять и возвращать текущий каталог. Так мы никогда не заблудимся!

#include <stdio.h>
#include <dir.h>
#include <string.h>

//Функция определения текущей папки
char *GetCurrentDir(char *path)
{
strcpy(path, "X:\\");
path[0]='A'+getdisk();
getcurdir(0, path+3);
return path;
}

void main()
{
char curdir[MAXPATH]; //объявляем строку

GetCurrentDir(curdir); //записываем в строку текущий путь

printf("\nТекущая папка %s", curdir);

//переходим на диск С, в корневой каталог.
chdir("c:\\");

//создаём папку c названием: "freedom"
mkdir("freedom");

//возвращаемся назад
chdir(curdir);

}

До сих пор мы использовали только стандартные библиотечные функции. Здесь мы впервые создали свою. В следующих главах мы очень подробно рассмотрим как создавать свои функции, здесь же хочу лишь заметить, что подставляя GetCurrentDir, на самом деле мы подставляем всё тело этой функции, которое объявили до функции void main. Эта функция записывает в переменную-аргумент текущий путь.

Функция getdisk - возвращает текущий диск. Так для диска А она вернёт 0, для диска В 1, для С 2 и т.д. По умолчанию мы записываем в переменную path А и прибавляем к ней возвращаемое значение. Таким образом мы получим не число, а символьное имя диска, на котором находимся. Функция getcurdir определяет дописывает к имени диска путь.

Резервируя массив символов curdir мы указали, что число символов MAXPATH. Эта константа одна из переменных окружения, в которой хранится длина максимального пути. Обычно она зависит от системы, в которой работает. В большинстве случаев, её значение 256.

Функция mkdir(*name) создаёт папку в текущем каталоге с указанным именем name.

Функцию GetCurrentDir вы можете использовать и в своих программах; она не будет меняться от программы к программе.

Вопрос: КАК удалить надоевшую папку?

Для того, чтобы удалить папку, должны быть соблюдены следующие условия: папка не должна быть открытой и она должна быть пустой. Если папка у вас открыта в одном из окон Windows или даже программой Far, её удаление может привести к критическому сбою системы, поэтому она будет блокировать все попытки удаления такой папки. Также защищены от удаления папки, в которых есть файлы. Для удаления пустой папки можно использовать следующий пример:

#include <stdio.h>
#include<dir.h>

void main()
{
int res;
chdir("c:\\");

res=rmdir("freedom");

if(!res) printf("Папка удалена");

else

printf("Не удаётся удалить папку");

}

В случае успешного удаления функция rmdir вернёт значение 0, если папка не существует, открыта или она не пустая, функция вернёт значение отличное от 0. Как же удалить папку, в которой есть файлы? - спросите вы. В Windows это делается очень просто. Вы показываете на папку, нажимаете Delete и поминай, как звали. Но для того, чтобы так просто удалить папку, нужно предусмотреть алогритм, который сначала удалит все файлы внутри папки, затем все вложенные папки и файлы в них, и только после этого удалит папку.

Вопрос: КАК получить атрибуты файла?

У каждого файла в системе есть атрибуты. Их можно всегда узнать, если щёлкнуть на файл правой кнопкой мыши и в контекстном меню выбрать "Свойства". Атрибутами файла принято считать: дату и время создания, размер, а также признак, является ли этот файл скрытым, архивным или системным.

Для начала узнаем дату и время создания файла. Для работы с атрибутами файлов и папок мы будем использовать библиотеку io.h ("input/output"), которая содержит в себе множество функций для работы с файлами на низком уровне.
В библиотеке io.h содержится структура ftime, которая хранит точные дату и время создания файла.

#include <dir.h>
#include <stdio.h>
#include <io.h>

void main()
{

FILE *stream; //создадим файловую переменную
struct ftime ft; //создадим экземпляр структуры ftime

stream=fopen("c:\\autoexec.bat","r"); //откроем файл для чтения

getftime(fileno(stream), &ft); //узнаем дату и время


printf("Время создания файла: %u:%u:%u\n", ft.ft_hour, ft.ft_min, ft.ft_tsec * 2); //%u - беззнаковый тип
printf("Дата создания: %u/%u/%u\n", ft.ft_month, ft.ft_day, ft.ft_year+1980);

fclose(stream); //Закрываем файл
getch();
}


Структура ftime - это объединение данных о дате и времени создания файла. Вызывая функцию getftime, мы заполняем поля этой структуры данными нашего файла. Для доступа к полям структуры мы создали экземпляр этой структуры ft. Через него мы получаем доступ к полям ft_hour, ft_min, ft_seс, которые хранят данные о файле. Все эти поля имеют тип unsigned - беззнаковый, поэтому для их вывода мы пишем %u.

Следующая программа предлагает ввести имя файла или папки (полный путь), после чего опеределяет являются ли файл или папка скрытыми, архивными или системными. Также она отличает файл от папки.

#include <stdio.h>
#include <dos.h>

void main()
{
char filename[128];
unsigned attrib; //беззнаковый тип

printf("Введите путь к файлу или папке:");
scanf("%s", filename);

if (_dos_getfileattr(filename,&attrib) != 0) //если путь не существует - ошибка и выход из программы
{
perror("Hевозможно получить аттpибуты файла!");
return 1;
}

//если файл только для чтения
if (attrib & _A_RDONLY)
printf("%s только для чтения.\n", filename);

//если файл скрытый
if (attrib & _A_HIDDEN)
printf("%s скpытый.\n", filename);

//если файл системный
if (attrib & _A_SYSTEM)
printf("%s системный.\n", filename);

//если это метка тома
if (attrib & _A_VOLID)
printf("%s это метка тома.\n", filename);

//если это папка
if (attrib & _A_SUBDIR)
printf("%s это папка.\n", filename);

//если файл архивный
if (attrib & _A_ARCH)
printf("%s аpхивный.\n", filename);

}


Вопрос: КАК прочитать дерево файлов?

Во многих программах используются диспетчеры файлов. В системе Windows они стандартные, когда дело касается выбора файла или папки. Но не всегда нас могут устроить стандартные диспетчеры файлов.
Не оглядываясь на Запад, мы можем сейчас создать программу, которая будет читать содержимое текущей папки и выводить в виде списка на экран. Вывод деревая файлов осуществляется тем же способом, что и поиск файлов в DOS, только мы ищем все файлы данной папки.
В языке Си существуют две функции: findfirst - для поиска первого файла, и findnext для всех остальных. Также, в библиотеке dir.h есть структура ffblk, в которой содержатся некоторые нужные нам атрибуты файла. Мы будем использовать те поля структуры, где находятся имена файлов и их размер.

#include <stdio.h>
#include <dir.h>
#include <conio.h>

void main()
{
clrscr();
struct ffblk f; //Создаём экземпляр структуры ffblk

int done;
printf("Содержимое каталога: \n");

done = findfirst("**.**", &ffblk, 0);

//Ищем пока есть файлы

while (!done)
{

printf(" %s\t", ffblk.ff_name); //Пишем имя файла
printf(" %d\n", ffblk.ff_fsize); //Пишем размер файла

done = findnext(&ffblk); //Ищем следующий такой файл
}

getch();
}

В данном случае функция findfirst задаёт условия поиска, а findnext мы вызываем в цикле до тех пор, пока в папке есть файлы. На экран будет выведен список всех файлов текущей папки. Данная конструкция допускает использование фильтров. Так, если бы нас интересовали только картинки в данной папке, можно было бы написать:

done = findfirst("**.JPG", &ffblk, 0);

И остальные файлы были бы отфильтрованы.

Основные возможности СИ для работы с файлами объединены в следующей таблице:

Функция
Краткое описание
fnmerge
создание имени файла из отдельных компонент
fnsplit
разбиение имени файла на компоненты
getcurdir
получить имя текущей папки
getdisk
получить имя текущего логического диска
searchpath
поиск файла а различных каталогах
setdisk
задать текущий диск
access
определить права доступа к файлу (только для ДОС)
chmod
изменение прав доступа к файлу (только для UNIX-подобных систем)
mktemp
генерация имени файла без участия пользователя
remove
уничтожение файла
rename
переименование/перемещение файла
setmode
установить новые значения параметра файла
chsize
изменение размера файла
fstat
получение информации о файле
locking
запирает область файла (только для ДОС)
stat
получение информации о файле
unmask
установка выбора режима работы с файлом
unlink
удаление файла


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


Назад Содержание Вперёд