1

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

我有大约 3000 行代码。一切都按预期工作。然而,我一直在想一个可能会扰乱我的项目的难题。

正在读取的文本文件(我们称之为 Text.txt)可能由单行或多行组成。

在我的例子中,一条“线”由它的段名称标识——比如 ISA、BHT、HB、NM1 等……每个段的结尾都由一个特殊字符“~”标识。

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

ISA.......~

NM1.......~

DMG.......~

瑟…………~

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

         ReadLn(myFile,buffer);

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


但是问题是...如果文件仅包含一行(由多个段组成)怎么办,表示为:-

ISA....... ~NM1....... ~DMG....... ~SE........ ~

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

我正在考虑创建一个 if,else 语句对......这取决于我的 Txt.txt 文件包含多少行......例如:-

if line = 1:- 然后一次提取每个段...由特殊字符“~”分隔执行必要的任务(3000 行代码) else if line > 1:- 然后一次提取每一行(对应于每个段)执行必要的任务(3000 行代码)。

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

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

4

2 回答 2

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;
于 2013-01-03T09:41:46.727 回答
0

我将通过 Win32 APICreateFileMapping()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;
于 2013-01-03T00:44:33.087 回答