将字符串从文本文件读取到Pascal中的Array中

Chr*_*ian 1 delphi pascal freepascal

使用此程序,我试图读取文件并将其随机打印到控制台。我想知道是否必须为此使用数组。例如,我可以将字符串分配到数组中,然后从数组中随机打印。但是,我不确定该如何处理。另一个问题是,当前程序无法从文件中读取第一行。我有一个text.txt包含

1. ABC
2. ABC
...
6. ABC
Run Code Online (Sandbox Code Playgroud)

下面是我的代码。

type
  arr = record 
  end;

var
  x: text;
  s: string;
  SpacePos: word;
  myArray: array of arr;
  i: byte;

begin
  Assign(x, 'text.txt');
  reset(x);
  readln(x, s); 
  SetLength(myArray, 0);
  while not eof(x) do
  begin
    SetLength(myArray, Length(myArray) + 1);
    readln(x, s);
    WriteLn(s);
  end;
end.
Run Code Online (Sandbox Code Playgroud)

请让我知道如何解决这个问题!

And*_*and 8

您的程序存在一些问题。

  1. 您的第Readln一个命令将文件的第一行读入s,但根本不使用此值。它丢失了。第一次Readln在循环中执行a 时,您将获得文件的第二行(使用确实将其打印到控制台Writeln)。

  2. arr在这种情况下(大多数情况下),您的记录类型完全没有意义,因为它是没有任何成员的记录。它不能存储任何数据,因为它没有成员。

  3. 在循环中,扩展数组的长度,一次扩展一项。但是您没有将新项目的值设置为任何值,因此您徒劳地这样做。(而且,由于前一点,在任何情况下都没有要设置的值:数组的元素是不能包含任何数据的空记录。)

  4. 一次增加一个动态数组的长度是一个很糟糕的做法,因为它可能每次都会导致新的堆分配。每次都可能需要将整个现有阵列复制到计算机内存中的新位置。

  5. 循环的内容似乎正在尝试做两件事:将当前行保存在数组中,然后将其打印到控制台。我认为后者仅用于调试?

  6. 旧式帕斯卡尔I / O( ,textAssignReset已经过时。它不是线程安全的,可能很慢,不能很好地处理Unicode等。它在90年代使用过,但今天不应该使用。相反,请使用RTL提供的功能。(在Delphi中,例如,你可以使用TStringListIOUtils.TFile.ReadAllLines溪流等)


该代码的部分固定版本可能看起来像这样(仍然使用老式的Pascal I / O和效率低下的数组处理):

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

var
  x: text;
  arr: array of string;

begin

  // Load file to string array (old and inefficient way)
  AssignFile(x, 'D:\test.txt');
  Reset(x);
  try
    while not Eof(x) do
    begin
      SetLength(arr, Length(arr) + 1);
      Readln(x, arr[High(Arr)]);
    end;
  finally
    CloseFile(x);
  end;

  Randomize;

  // Print strings randomly
  while True do
  begin
    Writeln(Arr[Random(Length(Arr))]);
    Readln;
  end;

end.
Run Code Online (Sandbox Code Playgroud)

如果要解决效率低下的数组问题,但仍不使用现代类,请分块分配:

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

var
  x: text;
  s: string;
  arr: array of string;
  ActualLength: Integer;


  procedure AddLineToArr(const ALine: string);
  begin
    if Length(arr) = ActualLength then
      SetLength(arr, Round(1.5 * Length(arr)) + 1);
    arr[ActualLength] := ALine;
    Inc(ActualLength);
  end;

begin

  SetLength(arr, 1024);
  ActualLength := 0; // not necessary, since a global variable is always initialized

  // Load file to string array (old and inefficient way)
  AssignFile(x, 'D:\test.txt');
  Reset(x);
  try
    while not Eof(x) do
    begin
      Readln(x, s);
      AddLineToArr(s);
    end;
  finally
    CloseFile(x);
  end;

  SetLength(arr, ActualLength);

  Randomize;

  // Print strings randomly
  while True do
  begin
    Writeln(Arr[Random(Length(Arr))]);
    Readln;
  end;

end.
Run Code Online (Sandbox Code Playgroud)

但是,如果您可以使用现代课程,那么事情会变得容易得多。以下示例使用现代的Delphi RTL:

泛型TList<T>自动处理有效的扩展:

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils, Generics.Defaults, Generics.Collections;

var
  x: text;
  s: string;
  list: TList<string>;

begin

  list := TList<string>.Create;
  try

    // Load file to string array (old and inefficient way)
    AssignFile(x, 'D:\test.txt');
    Reset(x);
    try
      while not Eof(x) do
      begin
        Readln(x, s);
        list.Add(s);
      end;
    finally
      CloseFile(x);
    end;

    Randomize;

    // Print strings randomly
    while True do
    begin
      Writeln(list[Random(list.Count)]);
      Readln;
    end;

  finally
    list.Free;
  end;

end.
Run Code Online (Sandbox Code Playgroud)

但是您可以简单地使用TStringList

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils, Classes;

var
  list: TStringList;

begin

  list := TStringList.Create;
  try

    list.LoadFromFile('D:\test.txt');

    Randomize;

    // Print strings randomly
    while True do
    begin
      Writeln(list[Random(list.Count)]);
      Readln;
    end;

  finally
    list.Free;
  end;

end.
Run Code Online (Sandbox Code Playgroud)

或者,您可以保留数组方法并使用IOUtils.TFile.ReadAllLines

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils, IOUtils;

var
  arr: TArray<string>;

begin

  arr := TFile.ReadAllLines('D:\test.txt');

  Randomize;

  // Print strings randomly
  while True do
  begin
    Writeln(arr[Random(Length(arr))]);
    Readln;
  end;

end.
Run Code Online (Sandbox Code Playgroud)

如您所见,现代方法更加方便(更少的代码)。它们也更快,并为您提供Unicode支持。


注意:上面所有片段均假定文件至少包含一行。如果不是这种情况,它们将失败,在真实/生产代码中,您必须对此进行验证,例如

  if Length(arr) = 0 then
    raise Exception.Create('Array is empty.');
Run Code Online (Sandbox Code Playgroud)

要么

  if List.Count = 0 then
    raise Exception.Create('List is empty.');
Run Code Online (Sandbox Code Playgroud)

// Print strings randomly零件之前,它假定数组/列表不为空。