Помощь - Поиск - Пользователи - Календарь
Полная версия: Файлы
Форум «Всё о Паскале» > Pascal, Object Pascal > Теоретические вопросы
Страницы: 1, 2
Unreal
Здравствуйте.
Нужна помощь... Как открыть файл, не зная его имя (задан только каталог, где находится)...
Заранее спасибо.
Altair
Какие-то данные о файле все же нужны.
Открыть его можно, в следующих случаях:
  • В заданном каталоге один файл
  • У файла уникальные атрибуты. (например у всех "архивный" а у этого "скрытый")
  • Файл отличается от остальных расширением (или отсутствием такого)
  • Известен размер файла.
  • Известно время создания файла
  • Можно открыть по очереди все файлы в каталоге
Во всех этих случаях надо использовать процедуру
FindFirst и в некоторых случаях FindNext. Обе они находятся в модуле DOS.
То есть для их использования, подключаем его:
Код

Uses Dos, {... другие модули};
{...}

Вызывается процедура следующим образом:
в разделе переменных, надо описать переменную, с типом SearchRec
Например:
Код

Uses DOS;
{...}Var
 A: SearchRec;
{... другие переменные}

Теперь в программе мы можем вызвать процедуру FindFirst:
Код
{...}
Begin
 FindFirst('*.TXT',AnyFile,A);
 {...}
end.

Поясняю:
Мы ищем ПЕРВЫЙ файл с расширением TXT в текущем каталоге, который может иметь любые(AnyFile) атрибуты.
Данные о файле (если он найден), помещаются в переменную A (она имеет тип SearchRec). Тип SearchRec имеет следующую структуру:
Код
Type SearchRec = Record
 Fill : Array [1..21] Of Byte;
 Attr : Byte;
 Time : Longint;
 Size : Longint;
 Name : Array [0..12] Of Char;
End;

Если файл не найден, то в переменную DosError помещается код ошибки 18 (нет больше файлов).
Если нам надо продолжить поиск (какие-то условия нас не устраивают), то мы вызываем процедуру FindNext ...
Но для ее вызова уже не надо указывать тип искомых файлов( их маску и атрибуты). Процедура FindNext вызывается всегда только после FindFirst.

Теперь, когда нужный файл найден:
Код
{ связываем файловую переменную с именем этого файла }
Assign (f,a.name);
{ и открываем его }
Reset(f)

Примечание:
Если файл текстовый, то открыть его таким образом можно только на чтение, или только на дозапись.
Unreal
Большое спасибо...
Кстати, у меня последний случай...
Altair
Пожалуйста smile.gif
В вашем случае (перебор всех файлов) можно использовать (нужно т.е.) цикл:
Код
{...}
findfirst( {...}
{...}
repeat
 findnext( {...}
 {...}
until DosError=18;
{...}
Unreal
FindFirst('*.TXT', AnyFile, A); ---> "Type mismatch"
Altair
Так стоп. Значит вы не правильно описали переменную A.
Покажите весь код (или хотя-бы ту часть, где переменные описываются и модули подключаются.
Unreal
Что там могло быть не правильно, я не осознал... Но к вечеру, прошу заметить, ЗАГРУЗИВ СВОЙ "НЕ РАБОТАЮЩИЙ" КОД, все прекрасно заработало...

Появился еще один вопрос, возможно ли открыть текстовой файл для продолжения записи, не стирая данные, как это делает ReWrite? И не прибегая к типизированным и нетипизированным файлам...

Код
Uses DOS;
Type SearchRec = Record
       Fill:Array [1..21] of Byte;
       Attr:Byte;
       Time:Longint;
       Size:Longint;
       Name:Array [0..12] of Char;
       end;
Var   a:SearchRec;
       f:Text;
       n:Integer;

Begin
FindFirst('*.TXT',AnyFile, a);
Assign (f,a.name);
Reset(f);
ReadLn(f,n);
WriteLn(n);
end.


Добавлено (17.06.04 11:51):
Да и еще... Какой командой табуляцию вызвать?...
Altair
Так, я понял, что первая проблемма с несовместимостью типов разрешена.
Эта ошибка могла быть по 3 причинам:
  • Вы находились в режиме отладки и надо было нажать RUN-> Program Reset
  • Надо было скомпилировать заново программу в память
  • неизвестная причина smile.gif
Файл на дозапись можно открыть процедурой append(f).
Процедуры для табуляции нет, но можно легко написать, просто записываем сначала нужное количество пробелов:
Код

var
i:byte;
f:text;
{...}
begin
for i:=1 to нужное_колическтво_пробелов do write(f,' ');
{...}

Не забываем, что writeln записывает в файл и переводит на новую строку,
а write просто пишет.
Я вообще никогда не пользуюсь writeln, а заменяю на альтернативную:
write('dfdsfdgsdfgsgsdgsd',#13,#10);
P.S.
Кстати, это же оптимизация .... пойду куда надо сообщу!
Unreal
Скорее третья причина... А каким образом в типизированном файле перейти на следующую строку?... А на счет табуляции, с пробелами не получится, выравнивать текст разной длины...
Altair
Цитата
Скорее третья причина...

Естественно ... :p5:
Цитата
А каким образом в типизированном файле перейти на следующую строку?...

Ой, кошмар какой! В типизированных файлах нет строк!
Там есть только элементы файла
Тут два случая:




  • При записи, переход на следующий эл-т осуществляесть автоматически



  • При чтении, переход осуществляется процедурой seek(f,n), где f -файловая переменная, а n- номер элемента, на который надо перейти.




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

Стоп, стоп, стоп!
Мы значит говорим о разных вещах.
Табуляция - это отступ от левого края на n символов.
А вы что под этим понимаете?
BlackShadow
Табуляция, насколько я помню, Олег, это выравнивание под определённую длинну, а не отступ, тем более от какого-то конкретного края.
Altair
Ага, понял ,это у меня ассоциация табуляции и клавиши TAB smile.gif Хотя выравнивание ИМХО называется форматирование текста.
Ну текст можно выравнить несколькими способами:
  • читаем из файла строку, если длинная, то остаток помещаем в буфер, потом читаем следующую, сразу в начало пишем из буфера, и проверяем длинну, ну и т.д (а если считываемая строка короткая, то добавляем пробелы)
  • Посимвольно перезаписываем файл, исключая символы управления (#13, #10), а потом, опять перезаписываем, только вставляя их куда надо.
Unreal
Такой еще вопрос: Создан ЕХЕ файл, при запуске которого идет обработка текстовых файлов... Как сделать, чтобы программа обрабатывала всегда только те файлы, которые лежат в ее каталоге, при этом местоположение ЕХЕ файла меняется?. Т.е. кинули в любую папку - запустили - обработала те файлы которые лежат в этой папке...
Altair
При связывании файла, надо не указывать полный путь к файлу, а только имя:
т.е. не так:
assign(f,'C:\windows\sss.txt');
А так:
assign(f,'sss.txt');
---------
Процедуры FindFirst и FindNext ищут файл в текущем каталоге.
Текущий каталог в программе - тот, в котором находиться эта прога.

Можно сменить текущий каталог процедурой CHDIR('каталог');
Unreal
Хорошо, а почему она обрабатывает только 10 файлов? Когда в каталоге 31...

Добавлено (19.06.04 4:28):
И еще... Где можно найти КОД процедупы READ?
Altair
2 причины:
1. Вы их 10 одновременно открываете.
(странно, тогда должно быть ограничение - 14 файлов )
2. Другие файлы не подходят по условию поиска (FindFirst)
может у остальных другое расширение или еще что.

А код выложить не можете?

Добавлено (19.06.04 4:39):
Цитата(Unreal)
Где можно найти КОД процедуры READ

Зачем??? blink.gif
Там-же чистый асм.
Если хотите заменить на более скоростную, то используйте BlockRead, только файл уже используйте нетипизированный.
Unreal
Есть ли процедура, с помощью которой текстовой файл можно открыть и для записи и для чтения, одновременно...?

Добавлено (19.06.04 8:37):
И возможно ли, во время работы в текстовом файле, вернуть курсор в начало файла?
Altair
Открыть текстовый файл одновременно для чтения и записи нельзя.
У меня была программка для чтения файла в память, там с ним можно делать все что угодно, а потом снова записывать на диск, могу ее поискать если надо.
Цитата
И возможно ли, во время работы в текстовом файле, вернуть курсор в начало файла?

Нет, не возможно. В этом недостаток текстовых файлов.
BlackShadow
Oleg_Z, а Reset(TextoviyFile) что сделает?
Unreal
-> BlackShadow... Если можно подробнее...
BlackShadow
Код

Var
 f:Text;
 s:String;
Begin
 Assign(f,'In.Txt');
 Reset(f);
 ReadLn(f,s);
 WriterLn(s);
 ReadLn(f,s);
 WriterLn(s);
 ReadLn(f,s);
 WriterLn(s);
 Reset(f);
 ReadLn(f,s);
 WriterLn(s);
 ReadLn(f,s);
 WriterLn(s);
 ReadLn(f,s);
 WriterLn(s);
 Close(f)
End.

Должно вывести две одинаковые тройки строчек.
Altair
Да, что-то я стормозил. (с кем не бывает)
Если файл уже открыт, то он сначала закрывается, а затем вновь
открывается. Текущая позиция указателя устанавливается на
начало файла.
А вот если надо на произвольные элемент переместить, то не выйдет с текстовыми.
BlackShadow
Я бы тоже не был так уверен...
Текстовый файл по сути своей запись типа TextRec (см. в "АЗЫ", я там о ней упоминал). Вот оттуда можно взять и вытянуть Handle файла (см. свой недавний вопрос), а затем уже дёргать указатель куда захочешь. Проблема только в том, что для установки на 30-ую строку придётся считать ещё 29 sad.gif Но доступ к n-ному символу осуществляется моментом smile.gif



Ладно, ладно - согласен, извращенец... Ну и что...
Altair
Цитата
Ладно, ладно - согласен, извращенец... Ну и что...

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

Кстати, а что будет, если текстовый файл описать как File of string?
Надо попробовать ...
BlackShadow
Попробуй, попробуй.
Только не забывай, что String - переменная "непостоянного" размера, а File Of может описываться для типов "фиксированного размера". Даже, если у тебя
Код
MyRec=Record
 a:Integer;
 b:String
End;

То File Of MyRec - не прокатит, а если
Код
MyRec=Record
 a:Integer;
 b:String[255]
End;

то File Of MyRec пойдёт, но считываться каждый раз будет по 258 байт.
Altair
Попробовал, не получилось.
(дальше для тех, кому интересно)
Код

Var
f:file of string;
fn:string;
n:longint;
begin
assign(f,'a');
rewrite(f);
fn:='aaaaa';
write(f,fn);
fn:='bbbbbbb';
write(f,fn);
close(f);
end.

Это запись файла.
В результате в файле a, если его читать как текстовый, будет:
aaaaa (потом до 256 символа пробелы), дальше:
bbbbbbb
И такая программа:
Код

Var
f:file of string;
fn:string;
n:longint;
begin
readln(fn);
assign(f,fn);
reset(f);
for n:=0 to filesize(f)-1 do begin seek(f,n); read(f,fn); writeln(fn); end;
close(f);
end.

Работать не будет (она ничего не выведет на экран).
Этот факт доказывает, что в памяти под простую строку резервируется 256 байт!
APAL
Может поиграться с "file of char;"?
Altair
Попробовать можно ...
Только потеряются особенности текстового ("строчность" )
BlackShadow
Не так уж и сложно написать что-нибудь типа Function GetString(F:TCharFile):String):String...
Stream
А вы в курсе, что в типизированном файле чтение происходит в тыщу раз медленнее, чем в техтовом...
Romtek
Stream, обоснуй.
virt
romtek
ну конечно не в тысячу ,но так как типизированный файл имеет некую гипотетическую структуру ,то процедура чтения как-то её анализирует.
если ты сам будешь считывать файл как символьный ,а потом решать что там к чему в нем и нет ли ошибки ,то получается что дольше.
BlackShadow
Бред.
P@sh@
точно бред, никакой проверки на корректность данных при типизированном чтении не происходит (имхо), а так как данные считываются блоками, будет еще быстрее, чем из текстового (там же каждый символ надо анализировать на конец строки)

впрочем, всякое может быть, я ни разу (!) в своей практике не использовал типизированные файловые переменные, только text (textfile в дельфе) для ведения всяческих логов и просто file для бинарного доступа
BlackShadow
То же самое...
Altair
Цитата
А вы в курсе, что в типизированном файле чтение происходит в тыщу раз медленнее, чем в техтовом...

Это бред!
Если на то пошло, то наоборот, процедуры для текстовых файлов работают медленнее процедур для типизированных и не типизированных.
Пример:
EOF работает в 2 раза медленнее, чем FileSize( при правильном использовании).
BlackShadow
EOF и FileSize - это 2 разные вещи. Пояни про что ты говоришь.
Altair
Конечно разные, я к тому что если использовать текстовый файл, то для проверки конца обычно используеться EOF, а в типизированных используют текущую позицию в файле и проверяют равна ли она FileSize.
BlackShadow
Oleg_Z прав. В общем случае EOF работает примерно так:
1) temp = FilePos;
2) size = Seek(end);
3) Seek(temp)
4) eof:=temp=size;
Ну, фигурально выражаясь. Под DOS пункты 1..3 выполняются одной и той же функцией. Единственное на яём может произойти экономия времени - на пункте 1, но я не помню хранится ли текущий указатель в переменной типа File. Судя по тому, что скорость падает в 2 раза, то храниться smile.gif
Altair
Кстати, а мне кажется есть хороший способ ускорить процедуру EOF .
Поробую ...

=== добавил позже, подумав smile.gif ===
Нельзя никак укорить эту функцию. Где-то прога хранит текущий указатель. Вот если найти где и как она хранит его ...
BlackShadow
Почитай доку по переменной типа File. Точно в одном из его полей храниться.
Altair
У переменной типа FILE есть поля????? blink.gif
Или я того ...
BlackShadow
Ты не того.
Что такое File? эЭто что, что-то типа Integer или Double? Нифига. Это структура, которая хранит в себе кучу инфы (не спроста она столько памяти кушает). В "Азах" я рассказывал про Dos.TextRec. Наверняка что-то есть и для "просто File", если не то же самое.
Romtek
{ Typed-file and untyped-file record }

 FileRec = record
             Handle: Word;
             Mode: Word;
             RecSize: Word;
             Private: array[1..26] of Byte;
             UserData: array[1..16] of Byte;
             Name: array[0..79] of Char;
           end;

{ Textfile record }

 TextBuf = array[0..127] of Char;
 TextRec = record
             Handle: Word;
             Mode: Word;
             BufSize: Word;
             Private: Word;
             BufPos: Word;
             BufEnd: Word;
             BufPtr: ^TextBuf;
             OpenFunc: Pointer;
             InOutFunc: Pointer;
             FlushFunc: Pointer;
             CloseFunc: Pointer;
             UserData: array[1..16] of Byte;
             Name: array[0..79] of Char;
             Buffer: TextBuf;
           end;


File - это указатель на структуру FileRec.
BlackShadow
Ну, судя по всему где-то в Private или UserData и лежит. Это продебугить надо...
Altair
Надо -же я открыл для себя новою инфу. Правильно сказанно - учиться, учиться, учиться, и так далее smile.gif

Надо поэксперементировать с FILE.
NetAnton
Вот на счет FILE здесь, Oleg_Z, ты правильно сказал. smile.gif
BlackShadow
Нечего над ним опыты ставить.
Проще самому написать под INT 21h - вот тебе по 2 (!) байта на файловую переменную.
Romtek
Народ, почаще заглядывайте в исходники модулей ТП...
Это взято из модуля DOS.PAS

Oleg_Z:
А лучше вообще не страдай фигнёй, а займись написанием какой-то игры.
BlackShadow
В таком случае скорость работы с файлом - очень важная штука.
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.