【问题标题】:Delphi: Save Multiline Strings to FileDelphi:将多行字符串保存到文件
【发布时间】:2014-12-18 18:26:17
【问题描述】:

大家晚上好。

我有一个 StringList,每条记录都包含一个多行字符串。

我的字符串列表 [0]:

<li>
  Test1
</li>

我的字符串列表 [1]:

<a href="#">
  <b>      
    Test2
  </b>
</a>

等等

如何将这些字符串保存并加载到文件(文本、ini、二进制、记录、savetofile 等)?主要问题是我可以将它保存到文本文件中,但是在回读时,每一行都被认为是一条新记录,而第一条记录有 3 行,第二条记录有 5 行,依此类推。

您对保存和加载这些字符串的过程有何建议?

【问题讨论】:

  • 如果将其保存为文本文件,则无法恢复信息。
  • 您的MyStringList[0] 是单行字符串。 &lt;li&gt; 不会导致换行; &lt;li&gt;Test1&lt;/li&gt; 在一行中是完全有效的 HTML。如果您将其与换行符一起写入文件,它将作为单独的行读回。如果你已经存储了&lt;li&gt;line break`Test1line break`,那么它就不是一个单行字符串。
  • @Ken 我认为字符串列表中的字符串包含换行符
  • 确实,它确实包含换行符:'
  • #10#13 Test1 #10#13
  • '
  • 你准备好保存一个单独的文件,说明在哪里放置换行符吗?
  • 标签: delphi tstringlist


    【解决方案1】:

    如果您将其保存到 .txt 文件中,您将无法正确重新加载它,因为您不知道给定换行符最初是嵌入在字符串中还是分隔两个字符串。

    如果您将其保存为另一种文本格式,例如.ini,您可以根据需要对换行符进行转义/取消转义,例如:

    function Encode(const S: String): String;
    begin
      Result := StringReplace(S, '<', '<<', [rfReplaceAll]);
      Result := StringReplace(Result, #13#10, '<CRLF>', [rfReplaceAll]);
      Result := StringReplace(Result, #13, '<CR>', [rfReplaceAll]);
      Result := StringReplace(Result, #10, '<LF>', [rfReplaceAll]);
    end;
    
    Ini := TIniFile.Create(...);
    try
      Ini.WriteInteger('section', 'count', MyStringList.Count);
      for I := 0 to MyStringList.Count-1 do
        Ini.WriteString('section', IntToStr(I), Encode(MyStringList[I]);
    finally
      Ini.Free;
    end;
    

    function Decode(const S: String): String;
    begin
      Result := StringReplace(S, '<LF>', #10, [rfReplaceAll]);
      Result := StringReplace(Result, '<CR>', #13, [rfReplaceAll]);
      Result := StringReplace(Result, '<CRLF>', #13#10, [rfReplaceAll]);
      Result := StringReplace(Result, '<<', '<', [rfReplaceAll]);
    

    结束;

    Ini := TIniFile.Create(...);
    try
      Count := Ini.ReadInteger('section', 'count', 0);
      for I := 0 to Count-1 do
        MyStringList.Add(Decode(Ini.ReadString('section', IntToStr(I), ''));
    finally
      Ini.Free;
    end;
    

    如果将其保存为二进制格式,则可以按原样保留换行符,例如:

    procedure WriteIntegerToStream(Stream: TStream; Value: Integer);
    begin
      Stream.WriteBuffer(Value, SizeOf(Integer));
    end;
    
    procedure WriteStringToStream(Stream: TStream; const Value: String);
    var
      U: UTF8String;
      Count: Integer;
    begin
      U := UTF8String(Value); // or UTF8Encode(Value) prior to D2009
      Count := Length(U);
      WriteIntegerToStream(Stream, Count);
      if Count > 0 then
        Stream.WriteBuffer(PAnsiChar(U)^, Count * SizeOf(AnsiChar));
    end;
    
    Strm := TFileStream.Create(..., fmCreate);
    try
      WriteIntegerToStream(Stream, MyStringList.Count);
      for I := 0 to MyStringList.Count-1 do
        WriteStringToStream(Stream, MyStringList[I]);
    finally
      Stream.Free;
    end;
    

    function ReadIntegerFromStream(Stream: TStream): Integer;
    begin
      Stream.ReadBuffer(Result, SizeOf(Integer));
    end;
    
    function ReadStringFromStream(Stream: TStream): String;
    var
      Count: Integer;
      U: UTF8String;
    begin
      Count := ReadIntegerFromStream(Stream);
      if Count > 0 then
      begin
        SetLength(U, Count);
        Stream.ReadBuffer(PAnsiChar(U)^, Count * SizeOf(AnsiChar));
        Result := String(U); // or UTF8Decode(U) prior to D2009
      end else
        Result := '';
    end;
    
    Stream := TFileStream.Create(..., fmOpenRead or fmShareDenyWrite);
    try
      Count := ReadIntegerFromStream(Stream);
      for I := 0 to Count-1 do
        MyStringList.Add(ReadStringFromStream(Stream));
    finally
      Stream.Free;
    end;
    

    【讨论】:

    • 您的二进制样本似乎不错。我会试一试。非常感谢
    • 那么您需要转义&lt;CRLF&gt; 的任何实例。二进制更干净。
    • @DavidHeffernan:或者至少转义 &lt; 字符,因为它们被保留用于转义。
    猜你喜欢
    相关资源
    最近更新 更多
    热门标签