错误使用 'file of char'

Wrong use of 'file of char'

我在使用这段代码时遇到问题,我有两个 char 文件,一个是关于书籍的信息,另一个是空的,我必须在 SAL 中写入一些来自 S 的信息,然后显示所有信息的总数许多书匹配代码的前 2 位数字,有多少是 R,有多少是 T。该代码确实将信息表 S 写入 Sal,但是当它应该显示总数时,它在屏幕上显示 ERORR 100。我读到了它,它说这是 'Disk read error' 的问题并且 *如果您 "seed" 一个不存在的类型文件记录并尝试 read/write 通常会发生此错误它。 *,我真的不懂

我一直在努力弄明白,但一直没能弄明白。我注意到,如果我不输入 'WHILE NOT EOF(S) DO',则不会出现错误,但当然我需要一段时间,如果有人能够指出我的错误,我将不胜感激。

这是代码:

uses crt;

var 
i : byte;
s,sal: file of char;
v,l1,l2: char;
cs,cn,cl: integer;

pn,ps,tot: integer;

BEGIN
 cs:=0; cn:=0;  i:=0; cl:=0;
Assign (s, 'C:\Users\te\Documents\s.txt');
     {$I-}
     Reset (s);
     {$I+}
     if IOResult <> 0 then
     begin
       writeln('Error');
       halt(2);  
     end;

      Assign (sal, 'C:\Users\te\Documents\sal.txt');
     {$I-}
     Rewrite (sal);
     IOResult;
     {$I+}
     if IOResult <> 0 then
       halt(2);  


    writeln('Please write the code of the book, only 2 digits');
    read(L1);read(L2);
    read(s,v);

    while (not eof(s)) do
    begin

      for i:=1 to 2 do
      read(s,v);

      if (v = '0') then
      begin
      read(s,v);
        if (v = '1') or (v = '2') then
        begin

        for i:=1 to 5 do
        read(s,v);

        if (v = 'R') then
        begin
        read(s,v);
        cs:= cs + 1;
        end
        else
        begin

        if (v = 'T') then
        begin
        cn:= cn + 1;
        read(s,v);
        end;
      end;

      while (v <> '-') do
      read(s,v);
      while (v = '-') do
      read(s,v);

      if (v = L1) then
      begin
      write(sal, v);
      read(s,v);
       if (v = L2)  then
       begin
       write(sal,v);
       read(s,v);
       cl:= cl + 1;
       end;
      end;

      while ( v <> '/') do
      begin
      write(sal,v);
      read(s,v);
      end;
      write(sal, '-');
      end

      else
      begin
      for i:= 1 to 5 do
      read(s,v);

      if (v = 'R') then
      cs:= cs + 1
      else
      cn:= cn + 1;

      if (v = L1) then
      read(s,v);
      if (v = L2) then
      begin
      cl:= cl + 1;
      read(s,v);
     end;
    end;

     end


     else
     begin
     for i:= 1 to 5 do
     read(s,v);

     if (v = 'R') then
     cs:= cs + 1
     else
     cn:= cn + 1;

     if (v = L1) then
     read(s,v);
     if (v = L2) then
     begin
     cl:= cl + 1;
     read(s,v);
     end;
    end;
    end;



    tot:= cs + cn;
    ps:= (cs * 100) div tot;
    pn:= (cn * 100) div tot;



    writeln('TOTAL ',cl);
    writeln();
    writeln(ps,'% and',pn,'%');

文件S内容:

02022013Rto kill a mockingbird-1301/02012014Tpeter pan-1001/02032013Thowto-2301/02012012Tmaze runner-1001/02012012Tmaze runner-1001/02012012Tmaze runner-1001/$

我真的只是需要别人对这段代码的看法,我想也许算法有缺陷。 谢谢

(在你编辑之后,我看到你的代码现在在 FPC 中编译 w/o 错误,很高兴你自己设法修复了错误)

因为这显然是课程作业,所以我不会为您修复您的代码,无论如何都会这样即便如此,我担心您会这样做是完全错误的。

基本上,您的代码的主要错误是您试图控制逐字符读取源文件时发生的情况。坦率地说,这是一种无望的尝试方式,因为它会使执行流程不必要地复杂化,并且充斥着 ifs、buts 和循环。它还要求您在任何给定步骤中始终在脑海中跟踪您尝试做的事情,并且生成的代码本质上是 而不是 自我记录 - 想象一下如果您回到您的代码六个月,你能一眼看出它是如何工作的吗?我个人当然不能。

您需要以不同的方式分解任务。不要自下而上地分析问题(“如果我接下来读这个字符,那么我接下来需要做的是......”)从上而下地分析问题:虽然你的输入文件是 file of char,它包含一系列字符串,由 / 字符分隔,最后由 $ 终止(但这个终止符并不重要)。所以你需要做的是逐个读取这些字符串-一个;一旦你得到一个,检查它是否是你要找的那个:如果是。按你需要的方式处理它,否则阅读下一个直到你到达文件的末尾。

一旦您成功阅读了其中一本书的字符串,您就可以将它拆分成由它组成的各个字段。执行此拆分最有用的函数可能是 Copy,它允许您从字符串中提取子字符串 - 在 FPC 帮助中查找它。我已经包含了函数 ExtractTitleExtractPreamble,它们向您展示了编写类似函数以提取 T/R 代码和连字符后面的数字代码所需执行的操作。顺便说一句,如果你以后需要问类似的问题,如果你在文件中包括对各个字段的布局和含义的描述,那将是非常有帮助的。

所以,我要向您展示的是如何通过逐个字符地构建字符串来读取 S.Txt 中的字符串系列。在下面的代码中,我使用函数 GetNextBook 来执行此操作,我希望它是合理的不言自明的。该代码在 while 循环中使用此函数来填充 BookRecord 字符串变量。然后,它只是将 BookRecord 写入控制台。当然,您的代码应该做的是处理 BookRecord 内容以查看它是否是您要查找的内容,然后执行您的任务的其余部分是否是。

我希望你会同意下面的代码比你 q 中的代码更清晰、更短并且将来更容易扩展。以这种方式构建程序的关键是将程序的任务分解为一系列函数和过程,每个函数和过程执行一个子任务。以这种方式编写程序可以更轻松地 "re-wire" 程序更改其功能,而无需重写 functions/procedures.

的内部结构
program fileofcharproject;

uses crt;

const
  sContents = '02022013Rto kill a mockingbird-1301/02012014Tpeter pan-1001/02032013Thowto-2301/02012012Tmaze runner-1001/02012012Tmaze runner-1001/02012012Tmaze runner-1001/$';
  InputFileName = 'C:\Users\MA\Documents\S.Txt';
  OutputFileName = 'C:\Users\MA\Documents\Sal.Txt';

type
  CharFile = File of Char; //  this is to permit a file of char to be used
                           //  as a parameter to a function/procedure

function GetNextBook(var S : CharFile) : String;
var
  InputChar : Char;
begin
  Result := '';

  InputChar := Chr(0);
  while not Eof(S) do begin
    Read(S, InputChar);
    // next, check that the char we've read is not a '/'
    //  if it is a '/' then exit this while loop
    if (InputChar <> '/') then
      Result := Result + InputChar
    else
      Break;
  end;
end;

function ExtractBookTitle(BookRecord : String) : String;
var
  p : Integer;
begin
  Result := Copy(BookRecord, 10, Length(BookRecord));
  p := Pos('-', Result);
  if p > 0 then
      Result := Copy(Result, 1, p - 1);
end;

procedure AddToOutputFile(var OutputFile : CharFile; BookRecord : String);
var
  i : Integer;
begin
  for i := 1 to Length(BookRecord) do
    write(OutputFile, BookRecord[i]);
  write(OutputFile, '/');
end;

function ExtractPreamble(BookRecord : String) : String;
begin
  Result := Copy(BookRecord, 1, 8);
end;

function TitleMatches(PartialTitle, BookRecord : String) : Boolean;
begin
  Result := Pos(PartialTitle, ExtractBookTitle(BookRecord)) > 0;
end;

var
  i : Integer; //byte;
  s,sal: file of char;
  l1,l2: char;
  InputChar : Char;
  BookFound : Boolean;
  cs,cn,cl: integer;
  pn,ps,tot: integer;
  Contents : String;
  BookRecord : String;
  PartialTitle : String;
begin
  //  First, create S.Txt so we don't have to make any assumptions about
  //  its contents

  Contents := sContents;
  Assign(s, InputFileName);
  Rewrite(s);

  for i := 1 to Length(Contents) do begin
    write(s, Contents[i]);  // writes the i'th character of Contents to the file
  end;

  Close(s);

  cs:=0; cn:=0;  i:=0; cl:=0;

  //  Open the input file
  Assign (s, InputFileName);
  {$I-}
  Reset (s);
  {$I+}
  if IOResult <> 0 then
  begin
    writeln('Error');
    halt(2);
  end;

  //  Open the output file
  Assign (sal, OutputFileName);
  {$I-}
  Rewrite (sal);
  IOResult;
  {$I+}
  if IOResult <> 0 then
   halt(2);

  //  the following reads the BookRecords one-by-one and copies
  //  any of them which match the partial title to sal.txt

  writeln('Enter part of a book title, followed by [Enter]');
  readln(PartialTitle);
  while not Eof(s) do begin
    BookRecord := GetNextBook(S);
    writeln(BookRecord);
    writeln('Preamble : ', ExtractPreamble(BookRecord));
    writeln('Title : ', ExtractBookTitle(BookRecord));
    if TitleMatches(PartialTitle, BookRecord) then
      AddToOutputFile(sal, BookRecord);
  end;

  //  add file '$' to sal.txt
  write(sal, '$');

  Close(sal);
  Close(s);

  writeln('Done, press any key');
  readln;

end.