МУ_ЛР7_ОП (1079938), страница 4
Текст из файла (страница 4)
{
_read( pFBin , &SBuf , sizeof(Student)); // Чтение из файла
printf ("ФИО = %s Курс = %d Стипендия = %f \n" , SBuf.Name, SBuf.Num , SBuf.Oklad);
};
_close( pFBin ); // Закрытие файла
Результат чтения файла
ФИО = Петров Курс = 1 Стипендия = 1000,000000
ФИО = Петров Курс = 2 Стипендия = 2000,000000
ФИО = Петров Курс = 3 Стипендия = 3000,000000
ФИО = Петров Курс = 4 Стипендия = 4000,000000
ФИО = Петров Курс = 5 Стипендия = 5000,000000
20 Навигация по файлу fseek, lseek
Обычно чтение и запись файлов выполняется последовательно. После чтения текущей записи (байта, строки, структуры) специальный указатель устанавливается на следующую позицию автоматически. Часто необходимо прочитать часть файла (запись, поле, строку, блок или байт) не последовательно, а выборочно. Для этого предусмотрены специальные функции перемещения текущего указателя: fseek – для потокового ввода/вывода и lseek – для низкоуровневого. После перемещения указателя в другое место мы можем прочитать любую запись или заменить существующую запись другой. Такие операции возможны для файлов, открытых в двоичном режиме. Покажем на примерах их применение.
При перемещении указателя мы может смещаться от начала файла (SEEK_SET) , конца файла(SEEK_END) и текущей позиции в файле (SEEK_CUR). Далее в функции задается смещение для нового чтения или записи. В нашем примере читается вторая запись от начала (для работы с записями на уровне потоков ввода и вывода):
// Позиционирование чтение
int Pos = 2 , PosNew ; // новые указателя читаем запись (Pos – 1) = 1 (2-я т.к. начнем с нуля )
Person PWork;
pF = fopen( "fwrite.out" , "r+b"); // Открытие для чтения
PosNew = fseek( pF, (Pos - 1)*sizeof(Person), SEEK_SET); // Перемещение указателя на новую позицию
fread( &PWork, sizeof(Person) , 1, pF);
printf( "Позиция персона из файла %s %f %d\n", PWork.Name , PWork.Stipen , PWork.Kurs );
fclose(pF); // Закрытие файла
Запись на место второй записи от начала:
// Запись по позиции Pos = 2
pF = fopen( "fwrite.out" , "r+b"); // Открытие двоичного файла для записи и чтения
Person PNew = {"Попов", 10000.0f , 10 };
PosNew = fseek( pF, (Pos - 1)*sizeof(Person), SEEK_SET);
fwrite( &PNew, sizeof(Person) , 1, pF);
flush( pF ); // Запись буфера на диск
rewind(pF); // указатель в начало файла
fread( &PWork, sizeof(Person) , 1, pF); // Контрольное чтение сначала
printf( "Позиция персона из файла %s %f %d\n", PWork.Name , PWork.Stipen , PWork.Kurs );
fclose(pF); // Закрытие файла
Для низкоуровневого ввода вывода перемещение указателя и прямое чтение будут выглядеть так:
// Чтение по позиции
long pos1 =3 , pos2; // Читаем вторую запись
pFBin = _open( "write.bin", _O_RDWR |_O_BINARY | _O_APPEND );
pos2 = _lseek( pFBin, sizeof(Student)* (pos1 - 1), SEEK_SET );
_read( pFBin , &SBuf , sizeof(Student));
_close( pFBin ); // Закрытие файла
Запись в середину и в конец файла:
// Изменение записи
pFBin = _open( "write.bin", _O_RDWR |_O_BINARY ); // Нет _O_APPEND
pos2 = _lseek( pFBin, sizeof(Student)* (pos1 - 1), SEEK_SET );
_read( pFBin , &SBuf , sizeof(Student)); // Чтение 3-й записи
pos2 = _lseek( pFBin, sizeof(Student)* (pos1 - 1), SEEK_SET );
strcpy(SBuf.Name, "Изменение"); // Запись на место 3-й записи
_write (pFBin , &SBuf , sizeof(Student));
// Добавление в конец файла
pos2 = _lseek( pFBin, 0L, SEEK_END );
Student S4 = {"APPEND END" , 4 , 15000.0f}; // Новая структурная переменная для записи
_write (pFBin , &S4 , sizeof(Student)); // Добавление в конец файла
_commit ( pFBin ); // Запись на диск после изменений
_close( pFBin ); // Закрытие файла
Результат чтения файла после всех изменений:
ФИО = Петров Курс = 1 Стипендия = 1000,000000
ФИО = Петров Курс = 2 Стипендия = 2000,000000
ФИО = Изменение Курс = 3 Стипендия = 3000,000000
ФИО = Петров Курс = 4 Стипендия = 4000,000000
ФИО = Петров Курс = 5 Стипендия = 5000,000000
ФИО = APPEND END Курс = 4 Стипендия = 15000,000000
21 Перенаправление потоков ввода и вывода
С помощью специальных функций можно стандартный поток перенаправить в файл. Для этого используется функция reopen. Пример:
/// ПЕРЕНАПРАВЛЕНИЕ ПОТОКА
pF = freopen( "out.txt", "w", stdout );
printf( "Позиция персона из файла %s %f %d\n", PWork.Name , PWork.Stipen , PWork.Kurs );
fclose(pF); // Закрытие файла
Такую возможность целесообразно использовать также при отладке программ для запоминания вывода и ввода при поиске ошибок.
22 Файл менеджеры
Для работы с файлами программисты, системные программисты и обычные пользователи могут использовать специальные программы, называемые файл менеджерами (FileManager), в частности это: Total Comander, Windows Comander, Far Manager и так далее. Для более подробного знакомства с такими утилитами операционной системы обратитесь к пособию по курсу [5], к разделу № 6. Кроме этого, вы можете воспользоваться справочными системами и информацией из Интернет.
Эти средства позволяют выполнить в удобной форме множества операций с файлами и каталогами: от поиска файлов, их просмотра и до их ручной модификации.
23 Работа с файлами целиком
При работе с файлами из программы могут понадобиться специальные действия: удаления файлов, копирование, их переименование. Для таких действий в системе ввода вывода Си есть специальные функции: remove (удалить), rename (переименовать) и другие. Кроме этого можно воспользоваться функцией system для выполнения любой доступной команды ОС. Примеры:
rename("Test1.txt" , "Test.txt");// Файл переименовать
remove("Test.txt"); // Нужно добавить файл "Test.txt" в текущий каталог
system(" chcp 1251 > nul");
system(" PAUSE");
system( "type fprintf.out" ); // Печатает весь файл
24 Работа со строками и консолью : sscanf, cprintf и sprintf
В заключение теоретической части ЛР обратим внимание на использование специальных функций (sscanf и sprintf), которые позволяют работать со строками в режиме форматированного ввода и вы вода. Кроме того, возможен чисто консольный ввод/вывод (<conio.h>): функции cprintf и cputs. Покажем это на примере:
char Str [80];
char buf1[80];
char buf2[80];
int num;
fgets (Str , 80 ,pF ); // ввод из файла в строку
sscanf( Str, "%s%s%d", buf1, buf2 , &num ); // ввод данных из строки Str
sprintf( Str, " ФИО=%s buf2 = %s num =%d", buf1, buf2 , &num ); // вывод данных в строку Str
// Консольный ввод и вывод
setlocale( LC_ALL, "" ); // Обязательная для консоли руссификация
cprintf( "Консольный -- '%s' '%s' '%d'\n" , buf1, buf2 , num );
_cputs( buf1 );
25 Примеры программы с использованием файлового ввода и вывода
Вторая часть задания, помимо первой связанной с изучением теоретического раздела заключается в том, чтобы испытать в проекте СИ уже отлаженные программы и фрагменты программ. Возможно, что, осваивая теоретическую часть работы, вы уже на компьютере проверили выполнение фрагментов текста и применения различных операторов ветвления (из раздела 3), тогда вам будет проще продемонстрировать их работу преподавателю. В дополнение к примерам, расположенным выше нужно испытать и изучить примеры расположенные ниже. Эти действия нужно сделать в отладчике.
Для этого нужно создать пустой проект в MS VS (Test_LR2), как описано выше, скопировать через буфер обмена в него текст данных примеров, отладить его и выполнить.
26 Примеры, описанные в теоретической части ЛР
Нужно внимательно изучить и проверить работу всех примеров из теоретической части ЛР. Эти примеры расположены выше. Все примеры можно скопировать в свой проект. Все эти задания выполняются обязательно, они не требуют дополнительной отладки и легко (через буфер обмена -Clipboard) переносятся в программу. Все фрагменты должны демонстрироваться преподавателю. В частности, в первой части, там представлены следующие примеры:
-
Работа с текстовыми и бинарными файлами(просмотр текста в файл менеджере)
-
Вычисление длины файла.
-
Запись и чтение символьного файла.
-
Запись и чтение файла построчно случайными данными.
-
Работа с функциями fread и fwrite.
-
Форматированный ввод и вывод в файлы.
-
Низкоуровневый ввод вывод в файлы.
-
Навигация по файлу fseek.
-
Работа с консольными функциями.
Кроме этого ниже представлены примеры, которые могут быть полезными, в том числе и при выполнении контрольных заданий. Их тоже нужно изучить и проверить.
Задачник Абрамова!!! Гл 13 , 14, 18, 22, 23, 27, 28, 29, 33, 35, 36
27 Формирование нового файла с вычисленными данными (fprintf).
Создаем файл и записываем в него 5 строк:
pF = fopen( "fprintf3.out" , "w+"); // Открытие файла для чтения
for (int i = 0 ; i < 5; i++)
fprintf (pF , "Строка - %d\n" , i + 1);
fclose(pF); // Закрытие файла
Файл (fprintf3.out) распечатан программой следующего раздела:
'Строка' '-' '1'
'Строка' '-' '2'
'Строка' '-' '3'
'Строка' '-' '4'
'Строка' '-' '5'
28 Чтение и распечатка текстового файла (файл создан и добавлен выше).
Программа чтения и распечатки текстового файла:
// Чтение из файла fscanf
pF = fopen( "fprintf3.out" , "r+"); // Открытие файла для чтения
for ( int i = 0 ; !feof(pF) ; i++)
{
char buf1[80];
char buf2[80];
int num;
fscanf( pF , "%s%s%d" , buf1,buf2, &num); // Ввод форматированных данных - разделитель пробел
if ( !feof(pF) )
printf( "'%s' '%s' '%d'\n" , buf1, buf2 , num ); // Печать данных из файла
};
fclose(pF); // Закрытие файла
Распечатан файл (fprintf3.out), сформированный в предыдущем разделе:
'Строка' '-' '1'
'Строка' '-' '2'
'Строка' '-' '3'
'Строка' '-' '4'
'Строка' '-' '5'
29 Добавление в файл вычисленными данными (fprintf ).
Добавляем в файл еще три строки с новыми параметрами:
pF = fopen( "fprintf3.out" , "a+"); // Открытие файла для чтения и добавления
for (int i = 0 ; i < 3; i++)
fprintf (pF , "СТРОКА - %d\n" , 10 + i + 1); // при добавлении ПРОПИСНЫЕ
fclose(pF); // Закрытие файла
Файл (fprintf3.out) распечатан программой предыдущего раздела:
'Строка' '-' '1'
'Строка' '-' '2'
'Строка' '-' '3'
'Строка' '-' '4'
'Строка' '-' '5'
'СТРОКА' '-' '11'
'СТРОКА' '-' '12'
'СТРОКА' '-' '13'
30 Запись из массива структур в файл
В нашем случае используется функция печати файла (StudPrintFileWR), печати структуры (PrintStudent) и функция перезаписи массива в файл (StudMasToFileWR). Для примера используем структуру Student:
// Структура для демонстрации
struct Student {
char Name[20];
int Num;
float Oklad;
};
// …
//Перезапись массива структур в файл (Файл предварительно очищается!) WR
void StudMasToFileWR( const char * FileName , Student * pMas , int Razm)
{
FILE * pF;
pF = fopen( FileName, "w+b"); // Открытие файла для записи
for ( int i = 0 ; i < Razm; i++)
fwrite( pMas + i, sizeof(Student) , 1, pF);
fclose(pF);
};
// Распечатка отдельной структурной переменной студента
void PrintStudent(Student * pS)
{
printf( "Запись: Имя = %-15s Номер = %2d Стипендия = %8.2lf \n",
pS->Name , pS->Num, pS->Oklad );
};
// Печать файла для стуктур типа Student
void StudPrintFileWR( const char * FileName)
{
FILE * pF;
pF = fopen( FileName , "rb"); // Открытие файла для чтения
Student SBuf;
while (!feof(pF) ) // Проверка конца файла
{
fread( &SBuf, sizeof(Student) , 1, pF); // чтение одной записи
if ( !feof(pF) )
PrintStudent(&SBuf);
};
// Закрытие файла















