Файлы и filemode. Глава 25, задание «г».

Книга адресована школьникам средних и старших классов, желающим испытать себя в «олимпийских схватках». Может быть полезна студентам-первокурсникам и преподавателям информатики.

Модераторы: Oleg_D, Модераторы

Файлы и filemode. Глава 25, задание «г».

Сообщение Парнишка » 21.01.2013 23:55:53

Готовлюсь по вашей книге к ЕГЭ по информатике, очень нравится, спасибо. Но в задании «г» главы 25 обнаружил существенный недочёт.

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

Вариант ответа:
Код: Выделить всё
var F1, F2: text;
begin
  Assign(F1, 'c:\autoexec.bat');
  Assign(F2, 'c:\autoexec.bat');
  Reset(F1);  Reset(F2);
  Writeln('OK!');
  Readln;
end.

Проблема в том, что в Free Pascal программа вылетает с «exitcode = 5».

Вот здесь мне обьяснили, что есть такой filemode и он по дефолту в Free Pascal равен 2, а должен быть равен 0. Действительно, filemode := 0 перед Reset(F1) исправило проблему, но я так и не понял, что такое filemode и зачем он должен быть равен 0.

Надеюсь, вы в следующем издании учебника укажете на filemode и обьясните мне и всем остальным что это такое.
Парнишка
незнакомец
 
Сообщения: 4
Зарегистрирован: 21.01.2013 23:39:23

Re: Файлы и filemode. Глава 25, задание «г».

Сообщение Oleg_D » 22.01.2013 09:27:18

Парнишка писал(а):Надеюсь, вы в следующем издании учебника укажете на filemode и обьясните мне и всем остальным что это такое.

Да, придётся сказать об этом хотя бы в ответах к задачам.
Вероятно, то своё решение я не проверял через FP, а в остальных компиляторах прекрасно работает и без обращения к FileMode (проверил в Borland Pascal, Delphi и PascalABC). Тут Free Pascal опять выделяется из общего строя :-)

А пока за дополнительной информацией желающие могут заглянуть сюда:

http://delphibasics.ru/FileMode.php
Oleg_D
постоялец
 
Сообщения: 391
Зарегистрирован: 09.05.2011 11:28:36

Re: Файлы и filemode. Глава 25, задание «г».

Сообщение bormant » 22.01.2013 11:56:36

На самом деле проблема в том, что FileMode НЕ ДОЛЖЕН применяться к файлам типа Text, и именно так и было в исходниках RTL из TP/BP (файловые функции для типа Text реализованы в исходном файле tfio.asm из rtlsys.zip, в нём НЕ содержится ссылок на переменную FileMode, определённую в system.pas; файловые функции для нетекстовых (не Text) файлов реализованы в fctl.asm, ссылка на FileMode присутствует (EXTRN FileMode:BYTE) и используется в функции ResetFile).

НЕ ДОЛЖЕН, поскольку в отношении текстовых (Text) файлов в явном виде запрещён Seek(), используется иная парадигма доступа -- последовательное устройство ввода/вывода:
ReSet() -- открытие для чтения, указатель в начале
Append() -- открытие для записи, указатель в конце
ReWrite() -- открытие для записи, указатель в начале
Аватара пользователя
bormant
постоялец
 
Сообщения: 407
Зарегистрирован: 21.03.2012 11:26:01

Re: Файлы и filemode. Глава 25, задание «г».

Сообщение Oleg_D » 22.01.2013 12:08:59

bormant писал(а):На самом деле проблема в том, что FileMode НЕ ДОЛЖЕН применяться к файлам типа Text

Вот и мне кажется, что не должен, но... Раз есть такая проблема, придётся сказать о ней.
Oleg_D
постоялец
 
Сообщения: 391
Зарегистрирован: 09.05.2011 11:28:36

Re: Файлы и filemode. Глава 25, задание «г».

Сообщение bormant » 22.01.2013 12:46:57

Посмотрел в RTL от FreePascal-2.6.0: rtl/inc/text.inc
Код: Выделить всё
Procedure FileOpenFunc(var t:TextRec);
var
  Flags : Longint;
Begin
  Case t.mode Of
    fmInput : Flags:=$10000;
    fmOutput : Flags:=$11001;
    fmAppend : Flags:=$10101;
  else
   begin
     InOutRes:=102;
     exit;
   end;
  End;
  Do_Open(t,PChar(@t.Name),Flags);
  ...
End;
FileMode также не используется. Затруднений с файлами "для чтения" нет:
Код: Выделить всё
$ echo "test line" > /tmp/test
$ chmod -w /tmp/test
$ ls -o /tmp/test
-r--r--r-- 1 user 10 янв.  22 12:38 /tmp/test
$ echo "test line 2" > /tmp/test
bash: /tmp/test: Отказано в доступе
Файл несомненно только для чтения. Выполняем:
Код: Выделить всё
var
  t: text; s: string;
begin
  assign(t, '/tmp/test'); reset(t);
  readln(t, s); writeln(s);
  close(t);
end.
Код: Выделить всё
$ ./testf
test line
По-прежнему никаких затруднений.

Полагаю, здесь несколько иная проблема -- разделение доступа и блокировки (SHARE_READ, SHARE_WRITE, SHARE_NONE), о которой однозадачному Dos задумываться почти не приходилось (за исключением доступа по сети).

Добавлено спустя 7 минут 49 секунд:
По поводу начального сообщения:
Код: Выделить всё
var
  t1, t2: text;
begin
  assign(t1, '/tmp/test'); assign(t2, '/tmp/test');
  reset(t1); reset(t2);
  writeln('Ok!');
  close(t2); close(t1);
end.
Код: Выделить всё
$ ./test2f
Ok!
Переменная FileMode, как и было показано выше, не влияет на файлы типа Text.
Надо будет при случае под Windows проверить.
Аватара пользователя
bormant
постоялец
 
Сообщения: 407
Зарегистрирован: 21.03.2012 11:26:01

Re: Файлы и filemode. Глава 25, задание «г».

Сообщение Oleg_D » 22.01.2013 13:15:37

bormant писал(а):Надо будет при случае под Windows проверить.

Вот под Windows-то я и проверил, -- действительно, глюк проявляется.
Парнишка писал(а):Готовлюсь по вашей книге к ЕГЭ по информатике

В плане подготовки к ЕГЭ те заморочки, что возникли с файлом, несущественны.
Oleg_D
постоялец
 
Сообщения: 391
Зарегистрирован: 09.05.2011 11:28:36

Re: Файлы и filemode. Глава 25, задание «г».

Сообщение bormant » 22.01.2013 15:29:29

Ага, в RTL от FPC на открытие текстовых файлов в Windows переменная FileMode всё таки влияет.
Смотрим в rtl/win/sysfile.inc:
Код: Выделить всё
procedure do_open(var f; p: pchar; flags: longint);
{
  filerec and textrec have both handle and mode as the first items so
  they could use the same routine for opening/creating.
  when (flags and $100)   the file will be append
  when (flags and $1000)  the file will be truncate/rewritten
  when (flags and $10000) there is no check for close (needed for textfiles)
}
Const
  file_Share_Read   = $00000001;
  file_Share_Write  = $00000002;
  file_Share_Delete = $00000004;
Var
  shflags, oflags, cd: longint;
  security: TSecurityAttributes;
begin
...
  { convert filesharing }
  shflags:=0;
  if ((filemode and fmshareExclusive) = fmshareExclusive) then
    { no sharing }
  else
    if (filemode = fmShareCompat) or ((filemode and fmshareDenyWrite) = fmshareDenyWrite) then
      shflags := file_Share_Read
  else
    if ((filemode and fmshareDenyRead) = fmshareDenyRead) then
      shflags := file_Share_Write
  else
    if ((filemode and fmshareDenyNone) = fmshareDenyNone) then
      shflags :=
{$ifdef WINCE}
        { WinCE does not know file_share_delete }
        file_Share_Read or file_Share_Write;
{$else WINCE}
        fmShareDenyNoneFlags;
{$endif WINCE}
...
  filerec(f).handle:=CreateFile(p,oflags,shflags,@security,cd,FILE_ATTRIBUTE_NORMAL,0);
...
end;
Если посмотреть на *nix-овую реализацию do_open() (rtl/unix/sysfile.inc), то там зависимости от переменной FileMode не увидим.
И для полноты картины режимы открытия и битовые маски разделения доступа:
Код: Выделить всё
const
  fmOpenRead       = $0000;
  fmOpenWrite      = $0001;
  fmOpenReadWrite  = $0002;

  fmShareCompat    = $0000;
  fmShareExclusive = $0010;
  fmShareDenyWrite = $0020;
  fmShareDenyRead  = $0030;
  fmShareDenyNone  = $0040;

Варианты fmShareDeny* пришли из MS-DOS, подробнее: http://blogs.msdn.com/b/larryosterman/a ... 31263.aspx (en) или перевод: http://www.transl-gunsmoker.ru/2009/04/ ... write.html (ru). Ещё подробнее -- в руководстве по MS-DOS.

Добавлено спустя 12 минут 30 секунд:
С учётом того, что атрибуты fmShareDeny* занимают старший полубайт, вот эта строчка:
Код: Выделить всё
if (filemode = fmShareCompat) or ((filemode and fmshareDenyWrite) = fmshareDenyWrite) then
      shflags := file_Share_Read
должна была бы выглядеть так:
Код: Выделить всё
if ((filemode and $f0) = fmShareCompat) or ((filemode and fmshareDenyWrite) = fmshareDenyWrite) then
      shflags := file_Share_Read
В этом случае при FileMode равном 2 файл будет открываться с разделением доступа на чтение (при этом собственно режим 2 -- fmOpenReadWrite в младшем полубайте при открытии текстового файла не используется, как и задумано).
А в существующем варианте нельзя задать fmShareCompat для открытия не в режиме чтения (не fmOpenRead).
Последний раз редактировалось bormant 22.01.2013 16:27:18, всего редактировалось 1 раз.
Аватара пользователя
bormant
постоялец
 
Сообщения: 407
Зарегистрирован: 21.03.2012 11:26:01

Re: Файлы и filemode. Глава 25, задание «г».

Сообщение Oleg_D » 22.01.2013 16:03:41

Замечательное расследование, bormant, браво! Шерлок Иванович отдыхает :-)
Будем надеяться, что в будущем сей глюк поправят.
А вы, Парнишка, пока не берите это в голову, в задачах к ЕГЭ таких проблем не будет.
Oleg_D
постоялец
 
Сообщения: 391
Зарегистрирован: 09.05.2011 11:28:36

Re: Файлы и filemode. Глава 25, задание «г».

Сообщение Парнишка » 22.01.2013 17:38:12

Oleg_D писал(а):А вы, Парнишка, пока не берите это в голову, в задачах к ЕГЭ таких проблем не будет.

Спасибо, продолжаю заниматься дальше.
Парнишка
незнакомец
 
Сообщения: 4
Зарегистрирован: 21.01.2013 23:39:23

Re: Файлы и filemode. Глава 25, задание «г».

Сообщение bormant » 22.01.2013 17:39:00

Отправил в багтрекер с приложением патча: http://mantis.freepascal.org/bug_view_a ... g_id=23725
Будем посмотреть за его судьбой.
Аватара пользователя
bormant
постоялец
 
Сообщения: 407
Зарегистрирован: 21.03.2012 11:26:01

Re: Файлы и filemode. Глава 25, задание «г».

Сообщение Парнишка » 22.01.2013 19:19:58

Надеюсь я вам ещё не надоел : нашёл ещё один небольшой недочёт, по моему мнению. Глава 25 задание «д»:
Усовершенствуйте программу«вопрос-ответ»(глава 16) с тем, чтобы
ответы хранились не в программе, а в отдельном текстовом файле. Тогда
пользователи программы сами смогут сочинять ответы.

Если ученик создаёт в Блокноте документ и заносит туда ответы на русском, скорее всего копируя ваши варианты ответов из главы 16, то программа, пытаясь их вывести, выдаёт кракозябры. Если я не ошибаюсь, это вызвано тем, что Free Pascal понимает только кодировку DOS (OEM 866), а вот обычный Блокнот как раз и не понимает эту кодировку, и не сохраняет в ней. Эта проблема легко решаема заменой русских ответов на английские, но почесать репу ученика всё равно заставит.
Парнишка
незнакомец
 
Сообщения: 4
Зарегистрирован: 21.01.2013 23:39:23

Re: Файлы и filemode. Глава 25, задание «г».

Сообщение bormant » 22.01.2013 20:16:37

Парнишка писал(а):Если ученик создаёт в Блокноте документ и заносит туда ответы на русском, скорее всего копируя ваши варианты ответов из главы 16, то программа, пытаясь их вывести, выдаёт кракозябры. Если я не ошибаюсь, это вызвано тем, что Free Pascal понимает только кодировку DOS (OEM 866), а вот обычный Блокнот как раз и не понимает эту кодировку, и не сохраняет в ней.

Если честно, дело тут не в Free Pascal-е, а в системе, системной консоли и её кодировке. Вот смотрите:
Код: Выделить всё
> notepad testcp.txt
Это текст в кодировке cp1251.
> type testcp.txt
▌Єю ЄхъёЄ т ъюфшЁютъх cp1251.
> chcp
Текущая кодовая страница: 866
> chcp 1251
> type testcp.txt
Это текст в кодировке cp1251.
Правда, с клавиатурой пока не знаю, возможно ли гладкое решение.

И симметричный вариант -- использование для набора текста консольной программы, например, редактора IDE Free Pascal или edit.

Или еще более универсальный -- использовать редактор, умеющий сохранять в различных кодировках (умеющий подсветку синтаксиса и проч ;-) ).
Аватара пользователя
bormant
постоялец
 
Сообщения: 407
Зарегистрирован: 21.03.2012 11:26:01

Re: Файлы и filemode. Глава 25, задание «г».

Сообщение Oleg_D » 22.01.2013 21:50:38

Парнишка писал(а):Надеюсь я вам ещё не надоел

Что вы! я рад всем посетителям форума. Вот и баг помогли нащупать.
А что касается текста, то даже в Ворде можно сохранить файл в DOS-овской кодировке: Файл --> Сохранить как и далее выбрать тип файла: простой текст.
Oleg_D
постоялец
 
Сообщения: 391
Зарегистрирован: 09.05.2011 11:28:36

Re: Файлы и filemode. Глава 25, задание «г».

Сообщение Paster Fob » 23.01.2013 05:59:23

Парнишка для работы с текстовыми файлами я использую редактор Notepad++ ,что и другим советую.В нём можно выбрать нужную кодировку.
Аватара пользователя
Paster Fob
постоялец
 
Сообщения: 188
Зарегистрирован: 22.02.2011 21:53:36
Откуда: Новосибирск.

Re: Файлы и filemode. Глава 25, задание «г».

Сообщение bormant » 13.02.2013 09:53:18

bormant писал(а):Отправил в багтрекер с приложением патча: http://mantis.freepascal.org/bug_view_a ... g_id=23725
Будем посмотреть за его судьбой.
Исправлено 29.01.2013, ревизия 23542, версия 2.7.1.
Аватара пользователя
bormant
постоялец
 
Сообщения: 407
Зарегистрирован: 21.03.2012 11:26:01

След.

Вернуться в Книга "Песни о Паскале"

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 0

Рейтинг@Mail.ru