Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Организация файла последовательного доступа




В С++ файлу не предписывается никакая структура. Для последовательного поиска данных в файле программа обычно начинает считывать данные с начала файла до тех пор, пока не будут считаны требуемые данные. При поиске новых данных этот процесс вновь повторяется.

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

Коля 12 Александр 52

то при модификации имени Коля на имя Николай может получиться следующее:

НиколайАлександр 52

Аналогично в последовательности целых чисел 12 –1 132 32554 7 для хранения каждого из них отводится sizeof(int) байт. А при форматированном выводе их в файл они занимают различное число байт. Следовательно, такая модель ввода-вывода неприменима для модификации информации на месте. Эта проблема может быть решена перезаписью (с одновременной модификацией) в новый файл информации из старого. Это сопряжено с проблемой обработки всей информации при модификации только одной записи.

Следующая программа выполняет перезапись информации из одного файла в два других, при этом в первый файл из исходного переписываются только числа, а во второй - вся остальная информация.

#include "fstream.h"

#include "stdlib.h"

#include "math.h"

void error(char *s1,char *s2="") // вывод сообщения об ошибке

{ cerr<<s1<<" "<<s2<<endl; // при открытии потока для файла

exit(1);

}

main(int argc,char **argv)

{ char *buf=new char[20];

int i;

ifstream f1; // входной поток

ofstream f2,f3; // выходные потоки

f1.open(argv[1],ios::in); // открытие исходного файла

if(!f1) // проверка состояния потока

error("ошибка открытия файла",argv[1]);

f2.open(argv[2],ios::out); // открытие 1 выходного файла

if(!f2) error("ошибка открытия файла",argv[2]);

f3.open(argv[3],ios::out); // открытие 2 выходного файла

if(!f3) error("ошибка открытия файла",argv[3]);

f1.seekg(0); // установить текущий указатель в начало потока

while(f1.getline(buf,20,' ')) // считывание в буфер до 20 символов

{ if(int n=f1.gcount()) // число реально считанных символов

buf[n-1]='\0';

// проверка на только цифровую строку

for(i=0;*(buf+i)&&(*(buf+i)>='0' && *(buf+i)<='9');i++);

if(!*(buf+i)) f2 <<::atoi(buf)<<' '; // преобразование в число и запись

// в файл f2

else f3<<buf<<' '; // просто выгрузка буфера в файл f3

}

delete [] buf;

f1.close(); // закрытие файлов

f2.close();

f3.close();

}

В программе для ввода имен файлов использована командная строка, первый параметр – имя файла источника (входного), а два других – имена файлов приемников (выходных). Для работы с файлами использованы функции – open, close, seekg, getline и gcount. Более подробное описание функций приведено ниже.

Ниже приведена программа, выполняющая ввод символов в файл с их одновременным упорядочиванием (при вводе) по алфавиту. Использование функций seekg, tellg позволяет позиционировать текущую позицию в файле, то есть осуществлять прямой доступ в файл. Обмен информацией с файлом осуществляется посредством функций get и put.

#include "fstream.h"

#include "stdlib.h"

void error(char *s1,char *s2="")

{ cerr<<s1<<" "<<s2<<endl;

exit(1);

}

main()

{ char c,cc;

int n;

fstream f; // выходной поток

streampos p,pp;

f.open("aaaa",ios::in|ios::out); // открытие выходного файла

if(!f) error("ошибка открытия файла","aaaa");

f.seekp(0); // установить текущий указатель в начало потока

while(1)

{ cin>>c;

if (c=='q' || f.bad()) break;

f.seekg(0,ios::beg); // перемещение указателя в начало файла

while(1)

{ if(((cc=f.get())>=c) || (f.eof()))

{ if(f.eof()) // в файле нет символа большего с

{ f.clear(0);

p=f.tellg(); // позиция ЕOF в файле

}

else

{ p=f.tellg()-1; // позиция первого символа большего с

f.seekg(-1,ios::end); // указатель на последний элемент в файле

pp=f.tellg(); // позиция последнего элемента в файле

while(p<=pp) // сдвиг в файле на один символ

{ cc=f.get();

f.put(cc);

if (--pp>0) f.seekg(pp); // проверка на невыход за начало файла

}

}

f.seekp(p); // позиционирование указателя в позицию p

f.put(c); // запись символа с в файл

break;

}

}

}

f.close();

return 1;

}

Каждому объекту класса istream соответствует указатель get (указывающий на очередной вводимый из потока байт) и указатель put (соответственно на позицию для вывода байта в поток). Классы istream и ostream содержат по 2 перегруженные компоненты-функции для перемещения указателя в требуемую позицию в потоке (связанном с ним файле). Такими функциями являются seekg (переместить указатель для извлечения из потока) и seekp (переместить указатель для помещения в поток).

istream& seekg(streampos pos);

istream& seekg(streamoff off, ios::seek_dir dir);

Сказанное выше справедливо и для функций seekp. Первая функция перемещает указатель в позицию рos относительно начала потока. Вторая перемещает соответствующий указатель на off (целое число) байт в трех возможных направлениях: ios::beg (от начала потока), ios::cur (от текущей позиции) и ios::end (от конца потока). Кроме рассмотренных функций в этих классах имеются еще функции tellg и tellp, возвращающие текущее положение указателей get и put соответственно

streampos tellg();

Создание файла произвольного доступа

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

Наиболее удобными для организации произвольного доступа при вводе-выводе информации являются компоненты-функции istream::read и ostream::write. При этом, так как функция write (read) ожидает первый аргумент типа const сhar* (char*), то для требуемого приведения типов используется оператор явного преобразования типов:

istream& istream::read(reinterpret_cast<char *>(&s), streamsize n);

ostream& ostream::write(reinterpret_cast<const char *>(&s),

streamsize n);

Ниже приведен текст программы организации работы с файлом произвольного доступа на примере удаления и добавления в файл информации о банковских реквизитах клиента (структура inf).

#include<iostream>

#include<fstream>

#include<string>

using namespace std;

Struct inf

{ char cl[10]; // клиент

int pk; // пин-код

double sm; // сумма на счете

} cldata;

Class File

{ char filename[80]; // имя файла

fstream *fstr; // указатель на поток

int maxpos; // число записей в файле

public:

File(char *filename);

~File();

int Open(); // открытие нового файла

const char* GetName();

int Read(inf &); // счивание записи из файла

void Remote(); // переход в начало файла

void Add(inf); // добавление записи в файл

int Del(int pos); // удаление записи из файла

};

ostream& operator << (ostream &out, File &obj)

{ inf p;

out << "File " << obj.GetName() << endl;

obj.Remote();

while(obj.Read(p))

out<<"\nКлиент -> "<<p.cl<<' '<<p.pk<<' '<<p.sm;

return out;

}

File::File(char *_filename) // конструктор

{ strncpy(filename,_filename,80);

fstr = new fstream();

}

File::~File() // деструктор

{ fstr->close();

delete fstr;

}

int File::Open() // функция открывает новый файл для ввода-вывода

{ fstr->open(filename, ios::in | ios::out | ios::binary| ios::trunc); // бинарный

if (!fstr->is_open()) return -1;

return 0;

}

int File::Read(inf &p) // функция чтения из потока fstr в объект p

{ if(!fstr->eof() && // если не конец файла

fstr->read(reinterpret_cast<char*>(&p),sizeof(inf)))

return 1; //

fstr->clear();

return 0;

}

void File::Remote() // сдвиг указателей get и put в начало потока

{ fstr->seekg(0,ios_base::beg); // сдвиг указателя на get на начало

fstr->seekp(0,ios_base::beg); // сдвиг указателя на put на начало

fstr->clear(); // чистка состояния потока

}

const char* File::GetName() // функция возвращает имя файла

{ return this->filename; }

void File::Add(inf cldata)

{ fstr->seekp(0,ios_base::end);

fstr->write(reinterpret_cast<char*>(&cldata),sizeof(inf));

fstr->flush();

}

int File::Del(int pos) // функция удаления из потока записи с номером pos

{ Remote();

fstr->seekp(0,ios_base::end); // для вычисления maxpos

maxpos = fstr->tellp(); // позиция указателя put

maxpos/=sizeof(inf);

if(maxpos<pos) return -1;

 

fstr->seekg(pos*sizeof(inf),ios::beg); // сдвиг на позицию,

// следующую за pos

while(pos<maxpos)

{ fstr->read(reinterpret_cast<char*>(&cldata),sizeof(inf));

fstr->seekp(-2*sizeof(inf), ios_base::cur);

fstr->write(reinterpret_cast<char*>(&cldata),sizeof(inf));

fstr->seekg(sizeof(inf),ios_base::cur);

pos++;

}

strcpy(cldata.cl,""); // для занесения пустой записи в

cldata.pk=0; // конец файла

cldata.sm=0;

fstr->seekp(-sizeof(inf), ios_base::end);

fstr->write(reinterpret_cast<char*>(&cldata),sizeof(inf));

fstr->flush(); // выгрузка выходного потока в файл

}

int main(void)

{ int n;

File myfile("file");

if(myfile.Open() == -1)

{ cout << "Can't open the file\n";

return -1;

}

cin>>cldata.cl>>cldata.pk>>cldata.sm;

myfile.Add(cldata);

cout << myfile << endl; // просмотр файла

cout << "Введите номер клиента для удаления ";

cin>>n;

if(myfile.Del(n) == -1)

cout << "Клиент с номером "<<n<<" вне файла\n";

cout << myfile << endl; // просмотр файла

}

 

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...