Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум «Всё о Паскале» _ Теоретические вопросы _ Файлы

Автор: Unreal 16.06.2004 19:31

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

Автор: Altair 16.06.2004 19:55

Какие-то данные о файле все же нужны.
Открыть его можно, в следующих случаях:

Во всех этих случаях надо использовать процедуру
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 16.06.2004 20:16

Большое спасибо...
Кстати, у меня последний случай...

Автор: Altair 16.06.2004 21:00

Пожалуйста smile.gif
В вашем случае (перебор всех файлов) можно использовать (нужно т.е.) цикл:

Код
{...}
findfirst( {...}
{...}
repeat
 findnext( {...}
 {...}
until DosError=18;
{...}

Автор: Unreal 17.06.2004 7:18

FindFirst('*.TXT', AnyFile, A); ---> "Type mismatch"

Автор: Altair 17.06.2004 11:06

Так стоп. Значит вы не правильно описали переменную A.
Покажите весь код (или хотя-бы ту часть, где переменные описываются и модули подключаются.

Автор: Unreal 17.06.2004 14:28

Что там могло быть не правильно, я не осознал... Но к вечеру, прошу заметить, ЗАГРУЗИВ СВОЙ "НЕ РАБОТАЮЩИЙ" КОД, все прекрасно заработало...

Появился еще один вопрос, возможно ли открыть текстовой файл для продолжения записи, не стирая данные, как это делает 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 17.06.2004 17:31

Так, я понял, что первая проблемма с несовместимостью типов разрешена.
Эта ошибка могла быть по 3 причинам:

Файл на дозапись можно открыть процедурой 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 17.06.2004 20:01

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

Автор: Altair 17.06.2004 20:16

Цитата
Скорее третья причина...

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

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

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

Стоп, стоп, стоп!
Мы значит говорим о разных вещах.
Табуляция - это отступ от левого края на n символов.
А вы что под этим понимаете?

Автор: BlackShadow 17.06.2004 20:36

Табуляция, насколько я помню, Олег, это выравнивание под определённую длинну, а не отступ, тем более от какого-то конкретного края.

Автор: Altair 17.06.2004 20:53

Ага, понял ,это у меня ассоциация табуляции и клавиши TAB smile.gif Хотя выравнивание ИМХО называется форматирование текста.
Ну текст можно выравнить несколькими способами:


Автор: Unreal 18.06.2004 19:13

Такой еще вопрос: Создан ЕХЕ файл, при запуске которого идет обработка текстовых файлов... Как сделать, чтобы программа обрабатывала всегда только те файлы, которые лежат в ее каталоге, при этом местоположение ЕХЕ файла меняется?. Т.е. кинули в любую папку - запустили - обработала те файлы которые лежат в этой папке...

Автор: Altair 18.06.2004 19:21

При связывании файла, надо не указывать полный путь к файлу, а только имя:
т.е. не так:
assign(f,'C:\windows\sss.txt');
А так:
assign(f,'sss.txt');
---------
Процедуры FindFirst и FindNext ищут файл в текущем каталоге.
Текущий каталог в программе - тот, в котором находиться эта прога.

Можно сменить текущий каталог процедурой CHDIR('каталог');

Автор: Unreal 18.06.2004 19:52

Хорошо, а почему она обрабатывает только 10 файлов? Когда в каталоге 31...

Добавлено (19.06.04 4:28):
И еще... Где можно найти КОД процедупы READ?

Автор: Altair 19.06.2004 8:33

2 причины:
1. Вы их 10 одновременно открываете.
(странно, тогда должно быть ограничение - 14 файлов )
2. Другие файлы не подходят по условию поиска (FindFirst)
может у остальных другое расширение или еще что.

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

Добавлено (19.06.04 4:39):

Цитата(Unreal)
Где можно найти КОД процедуры READ

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

Автор: Unreal 19.06.2004 10:51

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

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

Автор: Altair 19.06.2004 17:33

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

Цитата
И возможно ли, во время работы в текстовом файле, вернуть курсор в начало файла?

Нет, не возможно. В этом недостаток текстовых файлов.

Автор: BlackShadow 21.06.2004 1:37

Oleg_Z, а Reset(TextoviyFile) что сделает?

Автор: Unreal 21.06.2004 10:21

-> BlackShadow... Если можно подробнее...

Автор: BlackShadow 21.06.2004 14:55

Код

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 21.06.2004 16:45

Да, что-то я стормозил. (с кем не бывает)
Если файл уже открыт, то он сначала закрывается, а затем вновь
открывается. Текущая позиция указателя устанавливается на
начало файла.
А вот если надо на произвольные элемент переместить, то не выйдет с текстовыми.

Автор: BlackShadow 21.06.2004 17:04

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



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

Автор: Altair 21.06.2004 17:13

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

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

Кстати, а что будет, если текстовый файл описать как File of string?
Надо попробовать ...

Автор: BlackShadow 21.06.2004 17:17

Попробуй, попробуй.
Только не забывай, что 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 21.06.2004 17:29

Попробовал, не получилось.
(дальше для тех, кому интересно)

Код

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 21.06.2004 21:18

Может поиграться с "file of char;"?

Автор: Altair 23.06.2004 11:36

Попробовать можно ...
Только потеряются особенности текстового ("строчность" )

Автор: BlackShadow 23.06.2004 14:55

Не так уж и сложно написать что-нибудь типа Function GetString(F:TCharFile):String):String...

Автор: Stream 24.06.2004 9:40

А вы в курсе, что в типизированном файле чтение происходит в тыщу раз медленнее, чем в техтовом...

Автор: Romtek 24.06.2004 12:28

Stream, обоснуй.

Автор: virt 24.06.2004 19:36

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

Автор: BlackShadow 25.06.2004 15:56

Бред.

Автор: P@sh@ 25.06.2004 19:50

точно бред, никакой проверки на корректность данных при типизированном чтении не происходит (имхо), а так как данные считываются блоками, будет еще быстрее, чем из текстового (там же каждый символ надо анализировать на конец строки)

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

Автор: BlackShadow 25.06.2004 20:01

То же самое...

Автор: Altair 1.07.2004 16:37

Цитата
А вы в курсе, что в типизированном файле чтение происходит в тыщу раз медленнее, чем в техтовом...

Это бред!
Если на то пошло, то наоборот, процедуры для текстовых файлов работают медленнее процедур для типизированных и не типизированных.
Пример:
EOF работает в 2 раза медленнее, чем FileSize( при правильном использовании).

Автор: BlackShadow 1.07.2004 16:41

EOF и FileSize - это 2 разные вещи. Пояни про что ты говоришь.

Автор: Altair 1.07.2004 17:00

Конечно разные, я к тому что если использовать текстовый файл, то для проверки конца обычно используеться EOF, а в типизированных используют текущую позицию в файле и проверяют равна ли она FileSize.

Автор: BlackShadow 1.07.2004 17:25

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 1.07.2004 17:30

Кстати, а мне кажется есть хороший способ ускорить процедуру EOF .
Поробую ...

=== добавил позже, подумав smile.gif ===
Нельзя никак укорить эту функцию. Где-то прога хранит текущий указатель. Вот если найти где и как она хранит его ...

Автор: BlackShadow 1.07.2004 17:35

Почитай доку по переменной типа File. Точно в одном из его полей храниться.

Автор: Altair 1.07.2004 17:39

У переменной типа FILE есть поля????? blink.gif
Или я того ...

Автор: BlackShadow 1.07.2004 17:44

Ты не того.
Что такое File? эЭто что, что-то типа Integer или Double? Нифига. Это структура, которая хранит в себе кучу инфы (не спроста она столько памяти кушает). В "Азах" я рассказывал про Dos.TextRec. Наверняка что-то есть и для "просто File", если не то же самое.

Автор: Romtek 1.07.2004 18:23

{ 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 1.07.2004 18:25

Ну, судя по всему где-то в Private или UserData и лежит. Это продебугить надо...

Автор: Altair 1.07.2004 19:32

Надо -же я открыл для себя новою инфу. Правильно сказанно - учиться, учиться, учиться, и так далее smile.gif

Надо поэксперементировать с FILE.

Автор: NetAnton 1.07.2004 19:35

Вот на счет FILE здесь, Oleg_Z, ты правильно сказал. smile.gif

Автор: BlackShadow 1.07.2004 19:39

Нечего над ним опыты ставить.
Проще самому написать под INT 21h - вот тебе по 2 (!) байта на файловую переменную.

Автор: Romtek 1.07.2004 20:21

Народ, почаще заглядывайте в исходники модулей ТП...
Это взято из модуля DOS.PAS

Oleg_Z:
А лучше вообще не страдай фигнёй, а займись написанием какой-то игры.

Автор: BlackShadow 1.07.2004 20:38

В таком случае скорость работы с файлом - очень важная штука.

Автор: Romtek 1.07.2004 23:20

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