МУ_ЛР7_ОП (1079938), страница 3
Текст из файла (страница 3)
Такая строка может быть получена следующим оператором программы (файл - pF):
fprintf (pF , "Строка1 !!! %d %d " , 1,2);
Для бинарного файла такая распечатка выглядит так (целое число 2 – представлено во внутреннем машинном виде – “02”):
Адр.: Шестнадцатеричное представление |Символьное предст.
0000: C8 E2 E0 ED EE E2 00 00| 00 00 00 00 00 00 00 00|Иванов..........
0000: 00 00 00 00 00 00 00 00| 00 00 C9 42 02 00 00 00|................
Такие строки могут быть получены следующим фрагментом текста программы:
// Структура для вывода
struct Person { // Структура для примеров
char Name[24]; // Фамилия
float Stipen; // Стипендия
int Kurs; // Курс
};
// Описание и вывод
Person P1 = {"Иванов", 100.5f , 2 };
…
fwrite( &P1, sizeof(Person) , 1, pF);
…
В примерах текста и распечатках красным цветом отмечены значения, соответствующие друг другу. Обратите внимание, что в бинарном файле “2” кодируется как “0200”, младший и старший байты типа int ( двухбайтовый тип) расположены в обратном порядке.
14 Проверка конца файла и указатель чтения файла
При обработке (при чтении) файлов необходимо знать, при каких условиях цикл чтения записей может быть завершен. Другими словами нужно определить специальное условие конца файла. В общем, это может быть установлено в программе следующими способами:
-
Узнать заранее размер файла и считать число символов прочитанных из файла.
-
Проверить конец файла специальной функцией ( _eof или feof – End Of File).
-
Проверить чтение специального байта – EOF- End Of File.
-
Проверить значение числа байтов, полученных из файла к данному моменту, и оценить по этому значению фактическое завершение обработки файла (должно быть прочитано нуль байт) – например, функции fread или _read.
В примерах, рассматриваемых ниже, мы будем использовать различные способы проверки конца файла. Здесь покажем оператор для вывода размера открытого файла.
printf("Длина файла = %ld \n",_filelength (pF->_file));
Для вывода размера требуется дескриптор файла (_file), поэтому используется ссылка по указателю (pF->_file).
15 Работа с текстовым/двоичным файлом с байтами - символами
Для записи и чтения байтовых текстовых файлов используются функции fputc (putc) и fgetc (getc). Для проверки конца файла при чтении используется функция feof. Отметим, что таким способом можно работать и с текстовыми и с бинарными файлами (открытие "w+b").
Запись файла в цикле побайтно на основе строки (StrOut):
FILE *pF; // Структура описания файлов
…
// Вывод в файл
char StrOut[]="Пример строки для вывода в файл!\n";
pF = fopen( "fputc.out" , "w+");
char ch;
// Вывод в файл
for ( int i = 0 ; StrOut[i] != '\0' ; i++)
{
//putc( StrOut[i], pF ); // вывод одного символа
fputc( StrOut[i], pF ); // вывод одного символа
};
fclose(pF);
Чтение и посимвольная распечатка файла:
// Ввод из файла
pF = fopen( "fputc.out" , "r"); // Открытие для чтения
while ( !feof(pF))
{
char ch = getc(pF);
if ( !feof(pF) ) // Для вывода маленького 'я' если ch== EOF (это 'я')
printf( "%c", ch ); };
fclose(pF);
Результат чтения файла:
Пример строки для вывода в файл!
Если проверять просто символ конца файла (EOF):
…
if ( ! (ch== EOF) ) //
printf( "%c", ch ); };
…
то получим так (“я” не выводится на печать, а в файле есть!):
Пример строки дл вывода в файл!
16 Работа с текстовым файлом построчно
Для записи и чтения строковых текстовых файлов используются функции fputs (puts) и fgets (gets). Для проверки конца файла при чтении используется функция feof.
Запись файла в цикле построчно на основе чисел случайно сгенерированных для каждой строки:
////// Работа СО СТРОКАМИ
// Буфур ввода
char line[81]; // память для 80 символов + символ '\0'
…
// Вывод в файл (puts)
srand( (unsigned) time( NULL ) ); // для случайного числа и случайного начала последовательности
// srand( (unsigned) 1 ); // Если 1 то при новом запуске программы случайная
// последовательность возобновляется
rand(); // для сброса первого числа
//
pF = fopen( "fputs.out" , "w+"); // Открытие текстового файла для записи
// Генерация числа 1-100 и перевод в символьное и добавление к строке
for ( int i = 1 ; i < 6 ; i++) // цикл для 5-ти строк 1-5
{
strcpy( line , "Строка для puts - "); // начальная строка
unsigned int n = (unsigned int) (((double)rand()*99.0)/ (double)RAND_MAX);// 0 - 99 – номер добавки
char Num[10]; // Символьный буфер для перевода целого числа
strcat(line , itoa (n + 1 ,Num, 10 )); // при переводе + 1
strcat(line , " \n"); // добавим конец строки
fputs( line, pF ); // Вывод строки в файл
};
fclose(pF); // Закрытие файла
Чтение и построчная распечатка текстового файла:
// Ввод из файла (gets)
pF = fopen( "fputs.out" , "r"); //Открытие текстового файла для чтения
//
while (!feof(pF) )
{
fgets( line , 80 , pF ); // Чтение строки из файла
if ( !feof(pF) ) // Проверка конца файла
printf( "Строка из файла:%s", line); // Перевод строки в файле!
};
fclose(pF); // Закрытие файла
Результат чтения текстового файла по строкам (случайное число 1-100 приклеено к строке) приведен ниже. Обратите внимание, что символ конца строки (\n) считывается в строке из файла, он записан в предыдущем цикле. Если его не поставить, то функция fgets будет считывать по 80-т символов и может достигнуть конца файла (feof) раньше. Все строки не будут распечатаны. Кроме этого, размер буфера для чтения нужно увеличить.
Строка из файла: Строка для puts - 38
Строка из файла: Строка для puts - 29
Строка из файла: Строка для puts - 10
Строка из файла: Строка для puts - 35
Строка из файла: Строка для puts - 20
17 Двоичные/двоичные файлы и функции fread и fwrite.
Для работы с двоичными файлами используется специальный набор функций (fread и fwrite). Эти функции позволяют читать и записывать записи, непосредственно в/из структурные переменные. Строго говоря, файлы для этих функций могут быть и текстовыми, или открыты как текстовые. Для чисто двоичных файлов характерно использование специальных функций (_read и _write) и механизм непосредственного чтения и записи из файлов посредством операционной системы, причем без буферизации. Для демонстрации возможностей будем использовать специальную структуру - Person:
// Структура для вывода и вывода
struct Person { // Структура для примеров
char Name[24]; // Фамилия
float Stipen; // Стипендия
int Kurs; // Курс
}; //
FILE * pF;
…
Person MasPers [] = { {"Иванов", 10.5f , 1 } , {"Петров", 100.5f , 2 } , {"Сидоров", 1000.5f , 3 }};
…
Запись файла на основе инициализированного массива структур:
// Цикл для fwrite
pF = fopen( "fwrite.out" , "w+b"); // Открытие файла для записи
for ( int i = 0 ; i < sizeof(MasPers)/sizeof(Person); i++)
fwrite( &MasPers[i], sizeof(Person) , 1, pF);
fclose(pF);
Цикл чтения файла бинарного файла:
// Ввод из файла
pF = fopen( "fwrite.out" , "rb"); // Открытие файла для чтения
while (!feof(pF) ) // Проверка конца файла
{
fread( &PWork, sizeof(Person) , 1, pF); // чтение одной записи
if ( !feof(pF) ) // Можно ли печатать? Нет ли уже конца файла?
printf( "Персона из файла: %s %f %d\n", PWork.Name , PWork.Stipen , PWork.Kurs );
};
fclose(pF); // Закрытие файла
Результат чтения файла:
Персона из файла: Иванов 10.500000 1
Персона из файла: Петров 100.500000 2
Персона из файла: Сидоров 1000.500000 3
18 Форматированный ввод и вывод в файлы
Принципы и особенности форматированного ввода и вывода были рассмотрены в лабораторной работе № 1 по данному курсу. Здесь мы отметим, что форматирование полностью идентично. Для вывода в файлы функция printf должна быть заменена на функцию fprintf, а функция scanf должна быть заменена на функцию fscanf. Проверка конца файла может быть выполнена функцией – feof.
Запись файла fprintf2.out:
// Вывод в файл fprintf
pF = fopen( "fprintf2.out" , "w+"); // Открытие файла для чтения
for (int i = 0 ; i < 5; i++)
fprintf (pF , "Строка - %d\n" , i + 1);
fclose(pF); // Закрытие файла
Получили файл fprintf2.out ( распечатано с помощью копии из notepad):
Строка - 1
Строка - 2
Строка - 3
Строка - 4
Строка - 5
Чтение записанного файла, данные в файле должны быть разделены пробелами:
// Чтение из файла fscanf
pF = fopen( "fprintf2.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); // Закрытие файла
Результат чтения файла (прочитанные данные поставлены в одиночные кавычки '):
'Строка' '-' '1'
'Строка' '-' '2'
'Строка' '-' '3'
'Строка' '-' '4'
'Строка' '-' '5'
Все возможности форматированного ввода/вывода для стандартных потоков (дисплей и клавиатура) доступны и для файлового форматирования.
19 Низкоуровневый ввод и вывод в СИ
Для низкоуровневого ввода и вывода в СИ (“Low-Level I/O”) используются специальные функции для открытия/закрытия файлов и работы с ними. Для этого уровня характерно использование операционной системы напрямую, что, в конечном счете, обеспечивается более эффективную работу с файлами. Для открытия закрытия используют функции: _open и _close. Для ввода и вывода: _read и write. Для проверки конца файла функция _eof. В качестве дескриптора файла здесь используется переменная типа int. Рассмотрим примеры использования такого механизма ввода и вывода.
Библиотеки и константы низкоуровневого ввода и вывода подключаются так:
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <io.h>
Для описания и создание пустого файла нужно выполнить операторы:
int pFBin = 0; // Дескриптор файла
// Открытие файла для записи/чтения, создания и в двоичном режиме
pFBin = _open( "write.bin", _O_RDWR |_O_BINARY | _O_CREAT | _O_TRUNC , _S_IREAD | _S_IWRITE);
_close( pFBin ); // Закрытие файла
Структура “Студент” для демонстрации функций ввода вывода ( Low-Level I/O):
struct Student { // Сведения о студенте
char Name[20]; // Имя
int Num; // Номер
float Oklad; // Оклад
};
Запись файла с изменением цифровых данных строку Name не изменяем:
// Структуры для циклов
Student S1 ={"Петров" , 1 , 1000.0f}; // Для записи
// Открытие файла для записи/чтения и добавления
pFBin = _open( "write.bin", _O_RDWR |_O_BINARY | _O_APPEND );
// запись файла
for (int i = 1 ; i <= 5 ; i++)
{
S1.Num =i; // Номер
S1.Oklad =1000.0* i; // Стипендия
_write (pFBin , &S1 , sizeof(Student));
};
_close( pFBin ); // Закрытие файла
В некоторых ситуациях возникает необходимость в изменении атрибутов файлов. Такое изменение может быть выполнено следующими командами.:
// Изменение атрибутов файлов
char Comand[40];
strcpy (Comand , "attrib -R ");
strcat (Comand , "write.bin");
system( Comand );
//
strcpy (Comand , "attrib -A ");
strcat (Comand , "write.bin");
system( Comand );
Чтение файла:
Student SBuf = { "" , 0 , 0.0f }; // Пустая структура для чтения
pFBin = _open( "write.bin", _O_RDWR |_O_BINARY | _O_APPEND ); //Открытие для Чтения и записи
while ( _eof(pFBin) == NULL) // Функция _eof возвращает NULL, если не конец файла, иначе - 1















