阅读文本文件 - 单行与多行

时间:2013-01-02 23:58:14

标签: delphi-xe2

我正在处理一个特定的场景,我必须从文本文件中读取,解析它,从中提取有意义的信息,使用信息执行SQL查询,然后生成响应,输出文件。

我有大约3000行代码。一切都按预期工作。但是我一直在考虑一个可能会破坏我的项目的可能性。

正在读取的文本文件(我们称之为Text.txt)可能包含一行或多行。

在我的情况下,'line'由其段名称标识 - 例如ISA,BHT,HB,NM1等......每个段结尾由特殊字符'〜'标识。

现在,如果文件由多行组成(这样每行对应一个段);说: -

ISA .......〜

NM1 .......〜

DMG .......〜

SE ........〜

依此类推....然后我的代码基本上每次读取一行'(即每个段),一次一个,并使用以下命令将其存储到临时缓冲区中: -

         ReadLn(myFile,buffer);

然后根据每一行执行评估。产生所需的输出。没问题。


然而问题是......如果文件只包含一行(由多个段组成),表示为: -

ISA .......〜NM1 .......〜DMG .......〜SE ........〜

然后用我的ReadLine命令我读取整行而不是每个段,一次一个。这对我的代码不起作用。

我正在考虑创建一个if,else语句对...这是基于我的Txt.txt文件包含的行数。例如: -

如果line = 1: - 然后一次提取每个片段......由特殊字符'〜'分隔      执行必要的任务(3000行代码) 否则如果行> 1: - 然后一次提取每一行(对应每个段)      执行必要的任务(3000行代码)。

现在3000行代码重复两次,我发现复制并粘贴所有代码两次并不优雅。

如果我能得到一些关于如何解决这个问题的反馈,我将不胜感激,无论是单行文件还是多行文件...当我继续评估时,我只使用一个段一段时间。

2 个答案:

答案 0 :(得分:1)

有很多可行的方法可以做到这一点。哪种方法最适合您可能取决于这些文件的持续时间以及性能的重要性。

一个简单的解决方案是一次只读取一个字符,直到你达到你的代字号分隔符。 下面的例程ReadOneItem显示了如何完成此操作。

procedure TForm1.Button1Click(Sender: TObject);
const
  FileName = 'c:\kuiper\test2.txt';
var
  MyFile : textfile;
  Buffer : string;

  // Read one item from text file MyFile.
  // Load characters one at a time.
  // Ignore CR and LF characters
  // Stop reading at end-of-file, or when a '~' is read

  function ReadOneItem : string;
  var
    C : char;
  begin
    Result := '';

    // loop continues until break
    while true do
      begin

        // are we at the end-of-file? If so we're done
        if eof(MyFile) then
          break;

        // read in the next character
        read ( MyFile, C );

        // ignore CR and LF
        if ( C = #13 ) or ( C = #10 ) then
          {do nothing}
        else
          begin

            // add the character to the end
            Result := Result + C;

            // if this is the delimiter then stop reading
            if C = '~' then
              break;
          end;
      end;
  end;


begin
  assignfile ( MyFile, FileName );
  reset ( MyFile );
  try

    while not EOF(MyFile) do
      begin
        Buffer := ReadOneItem;
        Memo1 . Lines . Add ( Buffer );
      end;

  finally
    closefile ( MyFile );
  end;
end;

答案 1 :(得分:0)

我将通过Win32 API CreateFileMapping()MapViewOfFile()函数使用文件映射,然后按原样解析原始数据,扫描~个字符并忽略任何换行符您可能会在每个细分之间遇到。例如:

var
  hFile: THandle;
  hMapping: THandle;
  pView: Pointer;
  FileSize, I: DWORD;
  pSegmentStart, pSegmentEnd: PAnsiChar;
  sSegment: AnsiString;
begin
  hFile := CreateFile('Path\To\Text.txt', GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
  if hFile = INVALID_HANDLE_VALUE then RaiseLastOSError;
  try
    FileSize := GetFileSize(hFile, nil);
    if FileSize = INVALID_FILE_SIZE then RaiseLastOSError;
    if FileSize > 0 then
    begin
      hMapping := CreateFileMapping(hFile, nil, PAGE_READONLY, 0, FileSize, nil);
      if hMapping = 0 then RaiseLastOSError;
      try
        pView := MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, FileSize);
        if pView = nil then RaiseLastOSError;
        try
          pSegmentStart := PAnsiChar(pView);
          pSegmentEnd := pSegmentStart;
          I := 0;
          while I < FileSize do
          begin
            if pSegmentEnd^ = '~' then
            begin
              SetString(sSegment, pSegmentStart, Integer(pSegmentEnd-pSegmentStart));
              // use sSegment as needed...
              pSegmentStart := pSegmentEnd + 1;
              Inc(I);
              while (I < FileSize) and (pSegmentStart^ in [#13, #10]) do
              begin
                Inc(pSegmentStart);
                Inc(I);
              end;
              pSegmentEnd := pSegmentStart;
            end else
            begin
              Inc(pSegmentEnd);
              Inc(I);
            end;
          end;
          if pSegmentEnd > pSegmentStart then
          begin
            SetString(sSegment, pSegmentStart, Integer(pSegmentEnd-pSegmentStart));
            // use sSegment as needed...
          end;
        finally
          UnmapViewOfFile(pView);
        end;
      finally
        CloseHandle(hMapping);
      end;
    end;
  finally
    CloseHandle(hFile);
  end;