http://sulfurzona.com/
News
Service
Magazine
Software (Battle City Game, Wallpaper manager, Superpad, VG-NOW, Puzzle Game, Netler Internet Browser, ..)
Dune Game (Dune III, Dune IV, Cheats, Forum, ..)
Games free
Turbo Pascal (Assembler, Docs, Sources, Debbugers, ..)
Books (Docs for developers)
Forum
Guest book
Компьютерная диагностика двигателя автомобиля (адаптер К-линии)Компьютерная диагностика двигателя автомобиля (адаптер К-линии)
 
 
 

Паскаль для новичков (часть 27)

 

Навигация по файлу

 
Паскаль для новичковДля гибкости работы с файлами в Turbo Pascal предусмотрены дополнительные возможности.
  
Процедура Seek(var F; N : longint) позиционирует указатель на элемент N (нумерация с нуля) открытого файла, представленного файловой переменной F. После этого текущая позиция указателя файла установлена на N-й элемент и последующие операции чтения/записи будут проводиться с этой позиции. Если в качестве новой позиции в файле указать значение, равное или превышающее размер файла в элементах, то значение текущего указателя будет установлено на окончание файла.
  
Функция FileSize(var F):longint возвращает размер открытого файла, представленного файловой переменной F, в элементах базового типа.
  
Функция FilePos(var F):longint возвращает текущую позицию указателя (номер текущего элемента) открытого файла, представленного файловой переменной F.
  
Функция EoF(var F):boolean возвращает True если достигнут конец файла, и False если нет, где F – файловая переменная.
  
Процедура Truncate(var F) обрубает хвостовую часть файла начиная с текущей позиции в открытом файле, представленном файловой переменной F. Таким образом можно установить новый размер для открытого файла. Примеры:
 
var FileWord : file of word;
begin
Assign( FileWord, ‘c:datawords.dat’ );
Reset( FileWord );
Writeln(‘FileSize=’,FileSize(FileWord),‘word(s)’);
{ позиционируем указатель файла на хвост }
Seek( FileWord, FileSize( FileWord ) );
{ позиционируем указатель файла на середину }
Seek( FileWord, FileSize( FileWord ) div 2 );
{ укарачиваем файл на половину }
Truncate( FileWord );
Writeln(‘FileSize=’,FileSize(FileWord),‘word(s)’);
Close( FileWord );
end.
 

Специальные операции

 
Следует перечислить некоторые операции, предназначенные для манипуляций с элементами файловой системы MS-DOS – файлами и каталогами (папками).
  
Операция удаления файла Erase(var F) вызывается с указанием файловой переменной, при этом файл может быть не просто связан с файловой переменной, а ещё и открыт. В любом случае после вызова Erase закрывать файл не имеет смысла (закрывать нечего), поэтому строку Close( FileWord ) можно опустить:
 
begin
Assign( FileWord, 'words.dat' );
Reset( FileWord );
Erase( FileWord );
Close( FileWord );
end.
 
Операция переименования (переброски) файла Rename(var F; NewName : string) требует указания присоединённой файловой переменной и строку с новым именем файла:
 
begin
assign( FileWord, 'words.dat' );
Rename( FileWord, 'awords.dat' );
end.
 
при этом файл не следует открывать, иначе при выполнении команды Rename произойдёт ошибка “Error 5: File access denied.” (доступ к файлу запрещён), то бишь запрещён доступ к файлу “words.dat”, который следует переименовать. Данная ошибка может возникнуть ещё в случае, когда файл с новым именем уже существует, то есть если существует файл “awords.dat”. Если же переименовываемый файл отсутствует, то возникает ошибка “Error 2: File not found.” (файл не найден). Указание такого короткого имени файла (без пути) приемлемо лишь к файлу, который находится в текущей папке (с программой или установленной командой ChDir), а если необходимо файл не просто переименовать, но ещё и перебросить его в другое место на диске, то тогда следует указать новое имя файла и путь, куда его следует переместить Rename(FileWord,'d:awords.dat'). Так как файл открыт не был, то и закрывать его операцией Close не нужно. Есть маленький нюанс, который может повлечь большие неудобства, и состоит он в том, что при попытке перебросить файл с одного диска на другой произойдёт ошибка выполнения. Так строки
 
assign( FileWord, 'd:awords.dat' );
Rename( FileWord, 'c:awords.dat' );
 
вызовут ошибку “Error 17: Cannot rename across drives.” (нельзя переименовать за пределы диска). Отсюда вывод: можно переименовывать файлы в пределах одного диска.
  
Операция MkDir(S : string) создаёт новый подкаталог с именем S. Для создания папки “files” в текущей папке MkDir('files') и для создания новой папки в корневом каталоге D-диска MkDir('d:files').
  
Для удаления папки следует вызвать RmDir(S : string) с именем папки в текущем каталоге RmDir('files') или с указанием полного пути к папке RmDir('d:files').
  
Для смены текущей папки следует вызывать операцию ChDir(S:string) с именем папки как и для предыдущей операции, а проверить какая папка на данный момент является текущей можно при помощи процедуры GetDir(D:byte; var S:string) с указанием номера диска D и получением имени текущей папки в строке S. При этом следует указать номер диска 0 для текущего диска, или номера 1,2,3,4,5,… для дисков A,B,C,D,E,… соответственно. Пример:
 
var S : string;
begin
GetDir( 0, S );
writeln(S);
ChDir( 'd:files' );
GetDir( 0, S );
writeln(S);
end.
 
Чтобы перейти на один уровень дерева папок выше, следует выполнить ChDir('..') с двумя точками в качестве параметра.
  
Выполнение всех этих операций в определённой ситуации может вызвать ошибку и работа программы может быть прервана. Как с этим бороться, будет рассказано ниже.
  
Для получения информации о размере диска в байтах следует вызвать функцию DiskSize(Drive:Byte):longint стандартного модуля DOS, где параметр Drive указывает номер диска в соответствии со сказанным выше. При этом, если размер логического диска превышает 2Гб, то всё равно будет получен результат 2Гб.
 
Для получения информации о свободном пространстве (в байтах) на диске следует вызвать функцию DiskFree(Drive:Byte):longint модуля DOS. Аналогичная ситуация с 2Гб-ми.
  
Две последние функции тоже могут вызвать аварийное завершение программы при возникновении ошибки, если не выполнить директиву {$I–} и никак не влияют на значение, возвращаемое системной функцией IOResult, о которой пойдёт речь далее. Однако, данные функции в случае ошибки возвращают значение –1 если указанный диск отсутствует.
 
Ещё модуль DOS предоставляет несколько полезных подпрограмм. Функция FSearch(Path:PathStr; DirList:string):PathStr производит поиск файла с именем Path в текущей папке и если файл не найден, то выполняет поиск по каждому пути из списка DirList, где они перечислены через точку с запятой. При этом DirList может быть пустой строкой. В случае удачного поиска будет возвращена строка с именем искового файла, иначе будет возвращена пустая строка.
 
Получить полный путь к файлу можно вызвав функцию FExpand(Path:PathStr):PathStr, где Path – имя файла. Данная функция не проверяет наличие указанного файла на диске, а просто дополняет имя файла недостающими параметрами – именем текущего диска и путём к текущему каталогу.
 
Процедура FSplit(Path:PathStr; var Dir:DirStr; var Name:NameStr; var Ext:ExtStr) позволяет разложить полное имя файла Path на составляющие: путь к файлу в Dir, короткое имя файла в Name и окончание (расширение) имени файла в Ext. Примеры смотрите ниже.
  
Нельзя не упомянуть о двух очень полезных процедурах, которые позволяют строить конструкции поиска файлов и папок по указанному пути и маске.
 
Процедура FindFirst(Path:string; Attr:word; var S:SearchRec) производит поиск первого файла или папки по указанному пути Path и результат поиска заносит в переменную S типа SearchRec, который описан в модуле DOS как:
 
type
       SearchRec = record
        Fill : array [1..21] of byte;
        Attr : byte;
        Time : longint;
        Size : longint;
        Name : string[12];
       end;
 
 
 
 
 
данная структура не выдумана разработчиками Turbo Pascal, а продиктована интерфейсом сервиса MS-DOS. Имена полей говорят сами за себя. Однако, значения поля Attr следует расшифровать. Данное поле хранит признак элемента каталога, то есть, грубо говоря, это папка или файл.
  
Процедура FindNext(var S:SearchRec) предназначена для поиска каждого последующего элемента каталога, предварительно должна быть вызвана процедура FindFirst. Процедуры FindFirst и FindNext модифицируют значение переменной DosError, объявленной в модуле DOS, поэтому после выполнения любой из этих двух процедур следует проверять её значение. Если значение равно нулю, то поиск проведён успешно и можно продолжать поиск далее, если нет, то поиск не увенчался успехом вообще, или уже были найдены все элементы, отвечающие критериям Path. При этом параметр Path может быть либо пустой, тогда поиск будет проводиться в текущей папке, либо может содержать путь поиска и маску поиска. Основываясь на многолетней практике могу сказать, что параметр Attr процедурой FindFirst никак не учитывается, поэтому после очередного поиска следует проверять атрибут найденного элемента каталога. Вот пример поиска файлов по пути и маске:
 
procedure PrintFileList( Path, Mask : string );
begin
FindFirst( Path + Mask, AnyFile, Rec );
while DosError = 0 do begin
    if Rec.Attr = Archive then
        writeln( Path, Rec.Name, ' ', Rec.Size );
    FindNext( Rec );
    end;
end;
 
А это пример поиска папок:
 
procedure PrintDirList( Path, Mask : string );
begin
FindFirst( Path + Mask, AnyFile, Rec );
while DosError = 0 do begin
          if (Rec.Attr = Directory)
             and (Rec.Name <> '.')
             and (Rec.Name <> '..') then
             writeln( Path, Rec.Name, '' );
      FindNext( Rec );
      end;
end;
 
при этом отсекаем ненужное. А это пример, показывающий как использовать выше составленные процедуры:
 
uses Dos;
 
var Rec : SearchRec;
begin
{ ищем в текущей папке все файлы,
   которые начинаются с ‘file’}
PrintFileList( '', 'file*.*' );
readln;
{ ищем папки, вложенные в текущую папку }
PrintDirList( '', '*.*' );
readln;
{ ищем все файлы в корневом каталоге диска }
PrintFileList( 'd:', '*.*' );
readln;
{ ищем все папки в папке ‘d:install’}
PrintDirList( 'd:install', '*.*' );
end.
 
Я немного увлёкся рассмотрением модуля DOS, совсем забыв о главной сегодняшней теме.
 

Обработка ошибок ввода-вывода

 
При работе с файловой системой могут возникать разного рода курьёзы: то файл не найден, то к файлу нет доступа, то исчерпано место на диске, то дискета (магнитный накопитель) защищена, то пагода нелётная ;o)
  
В итоге, стараниями системы наша программа может быть прервана в самый неподходящий момент, как говорится “Только жениться собрался…” то бишь сохранить заветные данные на диск, а там глядишь уже всё свободное место закончилось.
  
Чтобы взять быка за рога, а в данном случае позволить обработать аварийную ситуацию самой программе, следует перед фрагментом кода с дисковыми операциями установить директиву {$I–}, тогда программа не будет завершена аварийно, но станет возможным получить код возникшей ошибки посредством вызова функции IOResult (0 если ошибки нет). Следует производить проверку возвращаемого значения данной функции после каждой дисковой операции, которая может вызвать ошибку, так как если возникла ошибка и сразу после этого функция IOResult не была вызвана, то дальнейшие дисковые операции будут заблокированы и проигнорированы. При этом данная функция возвращает код ошибки только раз, а затем обнуляет этот код и последующие вызовы этой функции будут давать нулевой результат, до тех пор, пока какая-нибудь ошибка не произойдёт снова.
Рассмотрим на примере:
 
var Res : word;
       S : string;
begin
Assign( FileWord, 'words.dat' ); {$I–}
Reset( FileWord ); {$I+}
Res := IOResult;
If Res<>0 then begin
    case Res of
     2 : S := 'File not found';
     3 : S := 'Path not found';
     5 : S := 'Access denied';
     6 : S := 'Invalid handle';
   10 : S := 'Invalid environment';
   11 : S := 'Invalid format';
   15 : S := 'Invalid drive';
   18 : S := 'No more files';
 100 : S := 'Read disk error';
 101 : S := 'Write disk error';
 150 : S := 'Disk write protected';
    else S := 'Unknow error';
    end;
    writeln( ‘Error: ’, S );
    Halt;
    end;
end.
 
так как выполнение процедуры Reset предполагает наличие открываемого файла, то вероятную ошибку или скорее последствия возникновения возможной ошибки можно предотвратить представленной конструкцией обработки оной. Есть и другой вариант, когда может быть предотвращено само возникновение ошибки, где задействованы подпрограммы FSearch, FExpand и FSplit:
 
uses Dos;
var S : string;
       FileWord : file of word;
       Dir : DirStr;
       Name : NameStr;
       Ext : ExtStr;
begin
S := FSearch( 'words.dat', 'c:' );
if S = '' then begin
   writeln('Error: File not found');
   Halt;
   end;
S := FExpand( S );
FSplit( S, Dir, Name, Ext );
writeln( ‘Found file with:’ );
writeln( 'Path ', Dir );
writeln( 'Name ', Name );
writeln( 'Ext ', Ext );
Assign( FileWord, S );
Reset( FileWord );
end.
 
Чтобы не возникало дополнительных ошибок из-за человеческого фактора, напомню следующее:
 
   Имя файла – это любое выражение строкового типа, построенное по правилам составления файловых имен в операционной системе MS-DOS, где имя может содержать не более восьми допустимых символов. Допустимые символы – это прописные и строчные латинские буквы, цифры, и символы: ! @ # $ % ^ & ( ) ' ~ – _
Имя файла может начинаться с любого допустимого символа.
   За именем может следовать расширение – последовательность не более трех допустимых символов, отделённая от имени точкой.
   Перед именем может быть указан так называемый путь к файлу: имя диска и/или имя текущего каталога, а также имена каталогов (папок) вышестоящих уровней.
   Имя диска – это один из символов A...Z, после которого следует двоеточие. Имена А: и В: ассоциируются с дисковыми накопителями на гибких магнитных дискетах (НГМД), имена С:, D:, … – соответственно с жесткими дисками (НЖМД). При использовании драйверов виртуальных дисковых устройств RAMDRIVE, VDISK, FAKECD такие имена могут относиться также к одному или нескольким эмулируемым дискам. Если имя диска не указано, то предполагаемое устройство по умолчанию – то, которое было установлено в операционной системе перед началом работы программы. Вслед за именем диска может идти имя каталога, содержащего файл. Когда имени каталога предшествует обратная косая черта, то путь к файлу начинается с корневого каталога, если черты нет – из текущего каталога. За именем каталога может следовать одно или несколько имен каталогов нижнего уровня (подкаталогов), а каждое из них должна предварять обратная косая черта. Весь путь к файлу отделяется от имени файла обратной косой чертой. Максимально допустимая длина имени файла вместе с путём к нему – 79 символов. Для этого в модуле DOS объявлен тип PathStr : string[79].
 
Продолжение следует…
 
© Владислав Демьянишин
 
 
Вы находитесь на официальном сайте Владислава Демьянишина - разработчика игры Dune IV (Dune 4). На нашем сайте Вы можете бесплатно скачать игры Dune IV (Dune 4), Battle City (Танчики с Dendy/Nintendo), читы к играм и многое другое. Также Вы можете скачать бесплатно программы и полезные утилиты. Все программы чистые, т.е. не содержат вирусов и иного вредоносного ПО. Предлагаю также посетить Марья искусница - сайт о рукоделии (http://mariya-iskusnica.ru).
 
 
 

Журнал > Программирование > Паскаль для новичков (Turbo Pascal, Assembler) > Паскаль для новичков (часть 27): Навигация по файлу
 
 
 
27
 
ВКонтакте
Facebook
 
 
 
На главную страницу На предыдущую страницу На начало страницы
 
 
Украинский портАл Украина онлайн Рейтинг@Mail.ru Рейтинг Сайтов YandeG Rambler's Top100