Основы программирования — второй семестр 08-09; Михалкович С.С.; I часть

Материал из Вики ИТ мехмата ЮФУ
Перейти к: навигация, поиск

Файлы

Введение

Файл — именованная область на диске, содержащая некоторую информацию.

Преимущества:

  1. Хранят данные в промежутках между запусками программ.
  2. Размер данных в файле может существенно превышать оперативную память компьютера.

Классификация файлов

Файлы обычно классифицируют по двум признакам:
1. По типу компонент:

  • текстовые;
  • двоичные:
типизированные;
бестиповые.

2. По способу доступа:

  • последовательный;
  • произвольный.

Текстовые файлы

Тип text. Состоят из строк переменной длины, в конце каждой из которых находится символ перехода на новую строку (#13#10 в Windows, #10 в Linux). В PascalABC.NET это константа NewLine.

Двоичные файлы: информация хранится в виде двоичного кода.

Типизированные файлы

Тип file of <type>. Содержат данные фиксированного типа <type>.

Бестиповые файлы

Тип file. Могут хранить данные различных типов.

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

Файл называется

файлом произвольного доступа, если можно перейти к его i-му элементу за время, не зависящее от размеров файла («за константное время»),
файлом последовательного доступа, если переход к i-му элементу требует количество операций, пропорциональное i («требует линейного времени»).

Все файлы, содержащие элементы разного размера могут иметь только последовательный доступ к элементам. Таковыми являются:

  • текстовые,
  • бестиповые файлы.

Типизированные файлы имеют произвольный доступ.

Понятие файловой переменной, файлового указателя

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

Закрытый файл можно:

  • переименовывать
  • перемещать
  • копировать
  • удалять

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

Паскаль-программа

var f: file of integer;
begin
  Assign(f, 'a.dat');
    {связывает файловую переменную f с файлом на диске 'a.dat'
    (файл на диске может отсутствовать)}
  
  //файл состоит из элементов (1, 2, 3)
  Reset(f);               //файловый указатель — на элемент "1"
  
  var x: integer;
  read(f, x);             //x = 1
                          //файловый указатель — на элемент "2"
  
  write(f, x + 4, 666);   //теперь файл состоит из элементов (1, 5, 666)
                          //файловый указатель — за концом файла

  {выполнить read(f, x) НЕЛЬЗЯ, т.к. произойдет
   ошибка времени выполнения
   "чтение за концом файла"}
  write(f, 777);          //можно
  
  Close(f);
end.

2 способа открытия файла

  1. Reset(f) — открытие текстового файла на чтение, а двоичного — на чтение и запись;
    файл должен существовать;
    файловый указатель — на начало файла;
  2. Rewrite(f) — создание нового файла (если такого файла не существовало) или обнуление существующего;
    файловый указатель — в начало;
    текстовые файлы при этом открываются только на запись, а двоичные — на чтение и запись;

Функция Eof(f) [расшифровывается как End Of File] возвращает true, если файловый указатель находился за концом файла.

После работы с данными в файле его необходимо закрыть с помощью Close(f).
Если, не закрывая, выполнить Reset(f), то файловый указатель просто перейдет к началу.

Буферизация в файлах

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

Наличие буфера ускоряет операции чтения и записи, поскольку они выполняются преимущественно не с внешним устройством (файлом), а с участком оперативной памяти.

Если забыть закрыть файл, открытый на запись, то можно потерять лишь данные, сохраненные в буфере.

Подпрограммы для работы с закрытыми файлами

procedure Rename(f, name);
       //переименовывает файл, связанyый с файловой переменной f, давая ему имя name 
procedure Erase(f);
       //удаляет файл, связанный с файловой переменной f 
function FileExists(name): boolean;
       //возвращает True, если файл с именем name существует 

function DeleteFile(name): boolean;
       //удаляет файл. Если файл не может быть удален, то возвращает False 
function RemoveDir(name): boolean;
       //удаляет каталог. Возвращает True, если каталог успешно удален 

function GetCurrentDir: string;
       //возвращает текущий каталог 
function SetCurrentDir(name): boolean;
       //устанавивает текущий каталог. Возвращает True, если каталог успешно установлен 
function CreateDir(name): boolean;
       //создает каталог. Возвращает True, если каталог успешно создан 

function ExtractFileName(name): string;
       //выделяет имя файла из полного имени файла name 
function ExtractFileExt(name): string;
       //выделяет расширение из полного имени файла name 
function ExtractFilePath(name): string;
       //выделяет путь из полного имени файла name 

Типичные ошибки ввода-вывода при работе с файлами

  1. Файл открыли, но забыли выполнить Assign.
  2. Открыли, но файла нет на диске (или нет прав доступа на чтение).
  3. Попытка считывания за концом файла.

Все эти ошибки нужно обрабатывать с помощью исключений.

Пример 1. Файл не существует.

Assign(f, 'a.dat');

try
  Reset(f);
  read(f, x);
  Close(f);
except
  writeln('Файл не существует');
end;

Оператор try..finally

try
  <действия, которые могут вызвать исключение>
finally
 <действия, которые надо выполнить независимо от того,
   произошло исключение, или нет>
end;

Этот оператор отличается тем, что не обрабатывает исключение, а лишь выполняет некоторое завершающее действие, которое должно быть совершено в любом случае. Для обработки нужен внешний блок try..except.

Пример 2. Попытка считывания за концом файла.

Assign(f, 'a.dat');

try
  Reset(f);
  try
    read(f, x);
  finally
    Close(f);
  end;
except
  writeln('Произошла ошибка ввода-вывода');
end;

Подпрограммы для работы с типизированными файлами

procedure Truncate(f)
       //Усекает типизированный файл f, отбрасывая все элементы с позиции файлового указателя 
function FileSize(f)
       //Возвращает количество элементов в типизированном файле f 
function FilePos(f)
       //Возвращает текущую позицию файлового указателя в типизированном файле f 
procedure Seek(f, i);
       //Устанавливает текущую позицию файлового указателя в типизированном файле f на элемент с номером i 

Варианты использования

  • Перейти на конец файла для добавления элементов:
Seek(f, FileSize(f));
  • Перейти на предыдущую позицию:
Seek(f, FilePos(f) - 1);

Пример 1. Добавить в конец файла 'a.dat' элемент 0 (при необходимости создать файл).

const
  fileName = 'a.dat';

var 
  f: file of integer;

begin
  Assign(f, fileName);
  if FileExists(fileName) then
  begin
    Reset(f);
    Seek(f, FileSize(f));
  end
  else
    Rewrite(f);
  
  write(f, 0);
  Close(f);
end.

Пример 2. Возведение всех элементов файла в квадрат.

const
  fileName = 'a.dat';

var 
  f: file of real;

begin
  Assign(f, fileName);
  Reset(f);
  
  for var i:=0 to FileSize(f)-1 do
  begin
    var x: real;
    read(f, x);
    Seek(f, i);
    write(f, x * x);
  end;

  Close(f);
end.

Пример 3. Использование типизированных файлов для работы с простейшими БД.
БД студентов 1.9
Опишем запись для одного студента:

type
  Student = record
    name: string[50];
    course, group: integer;
  end;

Замечание. В связи с тем, что типизированные файлы хранят данные фиксированного размера, а string — переменной длины, использовать его в типизированных файлах мы не можем. Для этого будем использовать строки фиксированной длиныstring[n] (строка длины n).

Пусть уже создан файл 'Group1course.dat'.
Задача. Найти Иванова и перевести его в 8 группу.

type
  Student = record
    name: string[50];
    course, group: integer;
  end;

const
  fileName = 'a.dat';
var 
  f: file of Student;

begin
  Assign(f, fileName);
  Reset(f);
  
  while not Eof(f) do
  begin
    var x: Student;
    read(f, x);
    
    if (x.name = 'Иванов') and (x.group = 11) then
    begin
      x.group := 10;
      Seek(f, FilePos(f) - 1);
      write(f, x);
      break;
    end;
  end;

  Close(f);
end.

Пример 4. Сортировка файла по возрастанию.

for var i:=FileSize(f)-2 downto 0 do
for var j:=0 to i do
begin
  Seek(f,j);
  read(f,x,y);
  if x>y then
  begin
    Seek(f,j);
    write(f,y,x);
  end;
end;

Подпрограммы для работы с текстовыми файлами

procedure Reset(f)
       //Открывает текстовый файл f ТОЛЬКО на чтение.
procedure Rewrite(f)
       //Открывает текстовый файл f ТОЛЬКО на запись, обнуляя его содержимое
procedure Append(f)
       //Открывает текстовый файл f на дополнение
       //Файловый указатель устанавливается за концом файла
function Eoln(f)
       //Возвращает True, если файловый указатель находится на символе конца строки в текстовом файле f 
function SeekEof(f)
       //Пропускает пробельные символы, после чего возвращает True, если достигнут конец текстового файла f 
function SeekEoln(f)
       //Пропускает пробельные символы, после чего возвращает True, если достигнут конец строки в текстовом файле f 

procedure read(f, a, b, c)
       //Считывает значения в переменные a, b, c;
       //Переменные могут быть числовых типов, символьного, строкового
procedure write(f, a, b, c)
       //Записывает значения переменных a, b, c в текстовый файл f;
       //Переменные могут быть числовых типов, символьного, строкового
procedure readln(f, a, b, c);
procedure writeln(f, a, b, c);
procedure readln(f);
procedure writeln(f);

Примеры использования

Пример 1. Обработка строк в текстовых файлах.
Пусть имеется функция, которая трансформирует строку и возвращает string:

function Transform(var s: string): string;

Применить указанную трансформацию ко всем строкам файла.

var
  f, f1: text;

begin
  Assign(f, 'a.txt');
  Assign(f1, 'b$.txt');
  Reset(f);
  Rewrite(f1);
  
  while not Eof(f) do
  begin
    var s: string;
    readln(f, s);     //Важно использовать readLN, т.к. она пропускает символы перехода
                      //на новую строку (если использолвать read, произойдет зацикливание)
    s := Transform(s);
    writeln(f1, s);
  end;
  
  Close(f);
  Close(f1);
  
  Erase(f);
  Rename(f1, 'a.txt');
end.

Пример 2. Сумма целых в текстовом файле.

var f: text;

begin
  var sum := 0.0;
  
  assign(f,'a.txt');
  reset(f);
  while not SeekEof(f) do
  begin
    var x: real;
    read(f,x);
    sum += x;
  end;
  close(f);
  writeln(sum);
end.

.NET-типы File и Directory и их статические методы

uses System.IO, System.Text;

begin
  &File.Copy('p1.pas','p2.pas',true);
  &File.Exists('p2.pas');
  var s: string := &File.ReadAllText('p1.pas');
  var s1: string := &File.ReadAllText('p1.pas',Encoding.Default);
  var ss: array of string := &File.ReadAllLines('p1.pas');
  &File.WriteAllLines('p3.pas',ss);
  &File.WriteAllText('p4.pas',s);
  &File.AppendAllText('p2.pas',s);
  &File.Move('p3.pas','p5.pas');
  &File.Delete('p5.pas');
  
  Directory.GetCurrentDirectory();
  Directory.SetCurrentDirectory('d:\w');
  var fnames: array of string := Directory.GetFiles('.');
  var dnames: array of string := Directory.GetDirectories('..');
  Directory.Exists('d:\w');
end.