【问题标题】:Delphi Console Application increase input character limitDelphi Console Application 增加输入字符限制
【发布时间】:2018-07-24 10:52:51
【问题描述】:

是否可以增加控制台应用程序接受readln 的字符数。

它似乎只允许你输入 254 个字符

在 Delphi 中重现

文件 > 新建 > 其他 > 控制台应用程序

修改代码如下

program Project3;

{$APPTYPE CONSOLE} 

{$R *.res}

uses
  System.SysUtils;

var MyTest : String;
begin
  try
    readln(MyTest);
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

将此字符串粘贴到正在运行的应用程序中(它是一个 300 个字符的字符串)

ABCDEFHIL1ABCDEFHIL2ABCDEFHIL3ABCDEFHIL4ABCDEFHIL5ABCDEFHIL6ABCDEFHIL7ABCDEFHIL8ABCDEFHIL9ABCDEFHI10ABCDEFHI11ABCDEFHI12ABCDEFHI13ABCDEFHI14ABCDEFHI15ABCDEFHI16ABCDEFHI17ABCDEFHI18ABCDEFHI19ABCDEFHI20ABCDEFHI21ABCDEFHI22ABCDEFHI23ABCDEFHI24ABCDEFHI25ABCDEFHI26ABCDEFHI27ABCDEFHI28ABCDEFHI29ABCDEFHI30

对我来说,它将字符串截断为 254 个字符

ABCDEFHIL1ABCDEFHIL2ABCDEFHIL3ABCDEFHIL4ABCDEFHIL5ABCDEFHIL6ABCDEFHIL7ABCDEFHIL8ABCDEFHIL9ABCDEFHI10ABCDEFHI11ABCDEFHI12ABCDEFHI13ABCDEFHI14ABCDEFHI15ABCDEFHI16ABCDEFHI17ABCDEFHI18ABCDEFHI19ABCDEFHI20ABCDEFHI21ABCDEFHI22ABCDEFHI23ABCDEFHI24ABCDEFHI25ABCD

【问题讨论】:

  • 我在 XE5 和 Tokyo 10.2.2 测试过
  • 这是控制台窗口本身的限制,而不是 RTL。 ReadLn() 运行一个读取循环,直到遇到一个bare-LF、CRLF 或CR+EOF 以停止读取。甚至 C# 的 Console.ReadLine() 默认情况下最多为 254 个字符,除非您手动增加缓冲区大小。
  • 我在想如果 Visual Studio C# 可以解决这个问题,delphi 一定有办法stackoverflow.com/questions/5557889/console-readline-max-length
  • 该 C# 方法正在重定向 Console.ReadLine() 以从附加到 STDIN 并使用自定义缓冲区读取的用户定义流中读取。在 Win32 API 术语中,这基本上就像调用 GetStdHandle(STD_INPUT_HANDLE) 然后在其上调用 ReadFile() (这确实有效,顺便说一句,我刚刚对其进行了测试,它可以很好地读取整个 300 个字符)。例如,您可以使用 THandleStreamTStreamReader 来包装它。

标签: delphi console-application


【解决方案1】:

AFAIK,您不能让 RTL 的 Readln() 函数接受更多字符(尽管在内部,它被编码为运行一个应该能够处理超过 254 个字符的循环)。默认情况下,当您将 300 个字符的测试字符串粘贴到控制台窗口时,它似乎在您按 Enter 之前停止在 254 处接收字符。

但是,您可以使用不同的方法 - 调用 GetStdHandle(STD_INPUT_HANDLE),然后在该 HANDLE 上调用 ReadFile() 以阅读您想要的任何内容。如果您使用至少 300 字节的缓冲区,它会很乐意接受您的 300 字符测试字符串:

program Project3;

{$APPTYPE CONSOLE} 

{$R *.res}

uses
  System.SysUtils, Winapi.Windows;

var
  buf : array[0..299] of AnsiChar;
  MyTest: AnsiString;//string;
  hStdIn: THandle;
  dwNumRead: DWORD;
begin
  try
    //Readln(MyTest);
    hStdIn := GetStdHandle(STD_INPUT_HANDLE);
    ReadFile(hStdIn, buf, sizeof(buf), dwNumRead, nil);
    SetString(MyTest, buf, dwNumRead);
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

然后,您可以让 RTL 为您处理缓冲,方法是将 HANDLE 包装在 THandleStreamTStreamReader 中(后者允许您指定缓冲区大小 - 默认为 1024 字节),例如:

program Project3;

{$APPTYPE CONSOLE} 

{$R *.res}

uses
  System.SysUtils, Winapi.Windows, System.Classes;

var
  MyTest : String;
  strm: THandleStream;
  reader: TStreamReader;
begin
  try
    //Readln(MyTest);
    strm := THandleStream.Create(GetStdHandle(STD_INPUT_HANDLE));
    try
      reader := TStreamReader.Create(strm);
      try
        MyTest := reader.ReadLine;
      finally
        reader.Free;
      end;
    finally
      strm.Free;
    end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

【讨论】:

    【解决方案2】:

    RTL 足够灵活,可以覆盖文件设备驱动程序的默认值。它甚至允许您编写自己的驱动程序,但根据您的需要,您需要做的就是提供一个足以容纳您的输入的缓冲区。

    没有任何file 参数Readln 使用全局Input 所以这就是你要修改的内容:

    program Project1;
    
    {$APPTYPE CONSOLE}
    
    {$R *.res}
    
    uses
      System.SysUtils;
    
    var MyTest : String;
        Buff: array[0..511] of Char;
    begin
      try
        TTextRec(Input).BufSize := SizeOf(Buff);
        TTextRec(Input).BufPtr := @Buff;
        ReadLn(MyTest);
      except
        on E: Exception do
          Writeln(E.ClassName, ': ', E.Message);
      end;
    end.
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-11-16
      • 1970-01-01
      • 2019-11-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多