【问题标题】:TFileStream write data to next lineTFileStream 将数据写入下一行
【发布时间】:2021-11-12 11:35:58
【问题描述】:

我正在操作 TFileStream,我想将数据写入下一行。

以下代码重写了前一个...

我可以做些什么来包装并让它在那里写下新的一行?

function TParserSkyecc.GenerateHTMLFile(pathHtml,out1,out2,out3,out4,out5 : String) : Boolean;
var FS: TFileStream;
begin
  FS := TFileStream.Create(pathHtml+'\filename.txt',fmCreate or fmOpenWrite or fmShareDenyNone);
  try
  FS.Seek(0,soFromBeginning);
    FS.WriteBuffer(Pointer(AnsiString(out1))^,Length(out1));
    FS.WriteBuffer(Pointer(AnsiString(out2))^,Length(out2));
    FS.WriteBuffer(Pointer(AnsiString(out3))^,Length(out3));
    FS.WriteBuffer(Pointer(AnsiString(out4))^,Length(out4));
    FS.WriteBuffer(Pointer(AnsiString(out5))^,Length(out5));
  finally
    FS.Free;
  end;
end;

【问题讨论】:

  • 现在是 2021 年,网络浏览器仍然无法执行原生 Pascal 代码...
  • @AndreasRejbrand 这不是针对网络浏览器的,它只是通过每次将数据添加到新行来将数据写入 .txt 文件
  • 我知道!我只是在开玩笑,因为您将代码插入为 HTML+JavaScript sn-p 而不是常规代码块。

标签: delphi delphi-2010


【解决方案1】:

更简单的编写方法是直接使用TStreamWriter 而不是TFileStreamTStreamWriter 在其构造函数中采用 TEncoding,并具有 WriteLine() 方法。例如:

function TParserSkyecc.GenerateHTMLFile(pathHtml,out1,out2,out3,out4,out5 : String) : Boolean;
var
  Filename: string;
  Writer: TStreamWriter;
begin
  Result := False;
  try
    Filename := IncludeTrailingPathDelimiter(pathHtml) + 'filename.txt'; // or: TPath.Combine(pathHtml, 'filename.txt')
    Writer := TStreamWiter.Create(Filename, False, TEncoding.ANSI);
    try
      Writer.WriteLine(out1);
      Writer.WriteLine(out2);
      Writer.WriteLine(out3);
      Writer.WriteLine(out4);
      Writer.WriteLine(out5);
      Writer.Flush;
      Result := True;
    finally
      Writer.Free;
    end;
  except
  end;
end;

或者,您可以改用TStringList

function TParserSkyecc.GenerateHTMLFile(pathHtml,out1,out2,out3,out4,out5 : String) : Boolean;
var
  Filename: string;
  SL: TStringList;
begin
  Result := False;
  try
    Filename := IncludeTrailingPathDelimiter(pathHtml) + 'filename.txt'; // or: TPath.Combine(pathHtml, 'filename.txt')
    SL := TStringList.Create;
    try
      SL.Add(out1);
      SL.Add(out2);
      SL.Add(out3);
      SL.Add(out4);
      SL.Add(out5);
      SL.SaveToFile(Filename, TEncoding.ANSI);
      Result := True;
    finally
      SL.Free;
    end;
  except
  end;
end;

【讨论】:

    【解决方案2】:
    uses System.Classes, System.SysUtils, System.IOUtils;
    
    VAR pathHtml : STRING;
    
    PROCEDURE Test(CONST TXT : STRING);
      VAR
        FS  : TStream;
        N   : TFileName;
        B   : TBytes;
    
      BEGIN
        N:=TPath.Combine(pathHtml,'filename.txt');
        IF NOT TFile.Exists(N) THEN
          FS:=TFileStream.Create(N,fmCreate OR fmShareDenyNone)
        ELSE BEGIN
          FS:=TFileStream.Create(N,fmOpenWrite OR fmShareDenyNone);
          FS.Position:=FS.Size
        END;
        TRY
          B:=TEncoding.ANSI.GetBytes(TXT);
          FS.WriteBuffer(B,LENGTH(B))
        FINALLY
          FS.Free
        END
      END;
    

    对实施的评论:

    1. 使用 TPath.Combine 组合目录和文件名
    2. 使用 TEncoding.ANSI.GetBytes 将 UNICODE 字符串转换为 ANSI。您在上面使用的版本是错误的,因为 UNICODE 字符串的 AnsiString 等效项的长度可能与 UNICODE 字符串 f.ex 的长度不同。当您的国家字符在 UNICODE 中作为一对编码但在 AnsiString 中作为单个字节编码时,您可能最终(尝试)写入比 AnsiString 转换产生的字节更多的字节。
    3. 小心使用 AnsiString(和 TEncoding.ANSI),因为它取决于运行程序的计算机的语言/区域设置。

    如果汤姆在 cmets 中所说的话: Asker 希望将字符串放在文件中的不同行上。 是真的,那么很简单。只需替换行

    FS.WriteBuffer(Pointer(AnsiString(out1))^,Length(out1));
    FS.WriteBuffer(Pointer(AnsiString(out2))^,Length(out2));
    FS.WriteBuffer(Pointer(AnsiString(out3))^,Length(out3));
    FS.WriteBuffer(Pointer(AnsiString(out4))^,Length(out4));
    FS.WriteBuffer(Pointer(AnsiString(out5))^,Length(out5));
    

    out1:=out1+#13#10; out2:=out2+#13#10; out3:=out3+#13#10;out4:=out4+#13#10; out5:=out5+#13#10;
    FS.WriteBuffer(Pointer(AnsiString(out1))^,Length(out1));
    FS.WriteBuffer(Pointer(AnsiString(out2))^,Length(out2));
    FS.WriteBuffer(Pointer(AnsiString(out3))^,Length(out3));
    FS.WriteBuffer(Pointer(AnsiString(out4))^,Length(out4));
    FS.WriteBuffer(Pointer(AnsiString(out5))^,Length(out5));
    

    将 CR/LF 附加到每一行。

    【讨论】:

    • “作为 UNICODE 字符串的 AnsiString 等价物的长度可能与 UNICODE 字符串的长度不同,例如,当您有国家字符时“这是错误的。 UnicodeStringUTF-16 字符串,因此字节数始终是字符数的两倍。例如,Test 使用 8 个字节编码,每秒为 0。
    • LENGTH SIZE :-) 令我惊讶的是,您似乎是对的 :-)。我原以为 U+0308 和 U+0061(变音变音符号 + 字母 a)会被转换为单个 Ansi 字符“ä”,但它会被转换为 2 个字符(¨a),我认为这是不正确的,但是嘿:-)。
    • 即使是在 Ansi 中不作为独立字符存在的 UNICODE 变音字符(但在 Ansi 中确实存在这个变音符号 + 字母的组合)也被转换为“?a”而不是“正确”的组合字符...
    • @AndreasRejbrand:另外,字节数不是字符数的两倍,因为 U+0308 + U+0061 是 一个 字符(显示时)但是 两个 代码点(因此是四个字节)。正确的说法是字节数总是代码点数的两倍 :-) 字符(在 UTF-16 中)并不总是等于单个代码点,当然也不等于单个 16 位字(超过 65536 UNICODE 中的字符,因此即使 UTF-16 也需要使用多个 16 位实体来描述某些字符)。这仅适用于 UTF-32。
    • 似乎没有回答这个问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-28
    • 1970-01-01
    • 2019-01-09
    相关资源
    最近更新 更多