Вывод и ввод данных в файл с помощью функций библиотеки периода выполнения (C Runtime Library), страница 2

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

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <conio.h>

char buff[_MAX_PATH];      // Глобальный буфер (строка символов)

                 // Эта функция открывает файл как для записи, так и для чтения

void OpenFile (FILE*& fp, char* mode)

{

if (gets(buff) == NULL )       // Пользователь вводит имя файла

  exit(-1);                     // Если он не ввел его, уходим

if ((fp = fopen(buff,mode))== NULL)    // Попытка открыть файл

{

  printf("\n Can't open %s\n",buff);

  exit(-1);

}

}

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

Для того, чтобы функция могла вернуть измененное значение адреса входного параметра (*), надо ей передать либо адрес адреса этой переменной (**), либо ссылку на адрес (*&).

Именно это мы делаем, когда указываем тип (FILE*&) первого параметра функции OpenFile. Так как мы хотим вернуть в вызывающую функцию адрес вновь созданной структуры типа FILE (то есть переменную типа FILE*), то мы передаем ссылку (FILE*&) на этот адрес. Иначе адрес, выданный функцией fopen останется видимым только внутри функции OpenFile и не вернется в функцию main (в теле которой будет стоять вызов нашей вспомогательной функции OpenFile). Этот момент вначале кажется достаточно сложным, поэтому постарайтесь уяснить получше то, как в языках С и С++ происходит передача параметра (он всегда копируется вызываемой функцией и она работает с этой копией, которая назад не возвращается). Если надо вернуть изменение, то следует работать косвенно. В языке С для этого использовался механизм передачи адресом, в С++ появился еще один механизм — передачи ссылкой.

Ниже приведены коды главной функции, в которой мы, предварительно открыв оба файла, посимвольно считываем коды из одного файла и также посимвольно записываем преобразованные коды в другой файл. Здесь используются функции fgetc (чтение одного символа), fputc (запись одного символа) и feof (проверка на конец файла), которые описаны в stdio.h. В переменной nChars ведется подсчет преобразованных символов.

Обратите внимание еще на один момент. Функция fgetc возвращает значение типа int (код введенного символа), но мы принимаем его в переменную char c; Вы можете изменить тип переменной на int и при этом программа будет работать так же, но не в Windows 2000. Если в ней задать тип int, то она будет пользоваться кодировкой Unicode, в которой вся программа теряет смысл.

void main()

{

FILE *fIn=0, *fOut=0;   // Входной и выходной потоки

puts ("\n Enter Source file name\n");

OpenFile (fIn,"rt");

puts ("\n Enter Target file name\n");

OpenFile (fOut,"wt");

char c;

for (int nChars=0; !feof(fIn); nChars++)   // Пока не достигнут конец входного потока

{           // Посимвольное чтение

  c = fgetc(fIn);

  if (127<c && c<176)  // Преобразование кодов

   c+=64;          // Русский алфавит разбит на 2 диапазона (см. шрифт Terminal)

  else if (223<c && c<240)

   c+=16;

  fputc(c,fOut);   // Посимвольная запись в выходной поток

}

printf ("\n %d characters has been written\n\n",nChars);

}

Чтобы проверить работу программы, надо иметь файл в кодировке DOS. Его можно создать так:

¨  Открыть Windows Notepad,

¨  Выбрать фонт Terminal,

¨  Переключить раскладку клавиатуры (русский язык) и набрать осмысленный текст, не глядя на экран (там будет безобразие),

¨  Записать в файл (например, T.txt), разместив его в папке с проектом нашего консольного приложения,

¨  Закрыть Notepad и запустить приложение,

¨  Указать имя входного файла (T.txt) и любое имя выходного файла (например, Out.txt),

¨  Проверить результат, открыв файл Out.txt, например, прямо в студии разработчика. Текст должен быть осмысленным (таким, каким вы его вводили, не глядя на экран).

Другая библиотека

Приведем пример более современного стиля работы с файлами. Мы будем пользоваться услугами одного из семейств функций Win32 API. Для этого надо подключить файл windows.h. который делает доступными функции (CreateFile, ReadFile, WriteFile, CloseHandle, SetFilePointer, DeleteFile). Мы также создадим простой класс MyFile, который инкапсулирует некоторую функциональность обработки файлов.

Кроме того, мы используем малую часть того, что умеет делать стандартная библиотека STL (Standard Template Library). В частности, она дает возможность работать с объектами класса string, который позволяет значительно более гибко управлять строками текста, чем известный вам тип char*. Обратите внимание на отсутствие расширения (.h). Это отличительный признак header-файлов библиотеки STL.

#include <iostream>

#include <string>

#include <windows.h>

using namespace std;   // Делает доступным пространство имен STL

class MyFile

{

private:

string m_Name;  // Имя файла

HANDLE m_hFile; // Описатель (дескриптор) файла

public:

bool m_bOpen;   // Флаг события: файл открыт

MyFile(string name);  // Конструктор

virtual ~MyFile();