テキストファイル、末尾の改行を取り除く方法

解決


ponta  2013-02-05 15:34:33  No: 43745  IP: 192.*.*.*

お世話になっております。
ファイルの中の末尾 #13#10 を取り除きたくて苦戦しています。

TStringListのSaveToFileは必ず最後に改行が入ってしまうのでダメでした。
Streamを使って改行を取り除こうとしたのですが、大きなファイルを扱うと
「メモリが足りません」と表示してしまいます。

何か方法、ヒントがありましたら、助言頂けますでしょうか?

大きなファイルだと、メモリが足りなくなる場合のソースです。

var
  SF,DF:TFileStream;
  buf:PChar;
  sz:integer;
begin
  SF:=TFileStream.Create(Edit1.Text,fmOpenRead);
  sz:=SF.Size;
  GetMem(buf,sz+1);
  SF.ReadBuffer(buf^,sz);
  buf[sz]:=#0;
  SF.Free;

  if (buf[sz-1] = #10) AND (buf[sz-2] = #13) then
  begin
    buf[sz-2] := #0;
    sz := sz -2;
  end;

  DF:=TFileStream.Create(Edit1.Text+'2' ,fmCreate);
  DF.WriteBuffer(buf^,sz);
  FreeMem(buf);
  DF.Free;
end;

編集 削除
ponta  2013-02-05 15:36:01  No: 43746  IP: 192.*.*.*

環境を書くのを忘れました。
WindowsXP,Delphi7 です。

編集 削除
take  2013-02-05 16:48:56  No: 43747  IP: 192.*.*.*

テキストエディタで適当に書いてみたので試していませんが

var
  fs : TFileStream;
begin
  fs := TFileStream.Create(Edit1.Text,fmOpenReadWrite);
  try
    fs.size := fs.size - 2;     // 末尾2バイトを破棄
  finally
    fs.free;
  end;
end;

#$0d#$0aのチェックは seek と reed を使えば

編集 削除
ponta  2013-02-06 07:37:00  No: 43748  IP: 192.*.*.*

take様、ありがとうございます。
ちょっとかっこ悪いソースなのですが、

var
  fs : TFileStream;
  S : String;
  b1,b2: Byte;
begin
  S := Edit1.Text;
  fs := TFileStream.Create(S,fmOpenReadWrite);
  try
    if fs.Size >= 2 then
    begin
      fs.Seek(fs.Size-2,soBeginning);
      fs.Read(b1, SizeOf(b1));
      fs.Seek(fs.Size-1,soBeginning);
      fs.Read(b2, SizeOf(b2));
      if (b1 = $0D) AND (b2 = $0A) then
        fs.size := fs.size - 2;     // 末尾2バイトを破棄
    end;
  finally
    fs.free;
  end;
end;

で約600MB位のファイルの最後が改行の場合、破棄する事が出来ました。
しかし1000MB位以上のファイルの場合、最後に改行があっても取得した文字
は$0d$0aを取得してくれず、違う文字を取得しているようです。
seek を fs.Position := fs.Size -2; にしても同様に違う文字が取得されます。
何かオーバーフローとか、間違いを起こしているのでしょうか。

気づいた所がありましたら、教えて頂けますか?

編集 削除
take  2013-02-06 08:26:34  No: 43749  IP: 192.*.*.*

seekが取り得る値が-2147483648..2147483647  ですので
2Gバイト以上だと処理できないかもしれません。
(Delphi7での話)

末尾から指定するというやりかたではどうでしょうか?

seek(-2,soFromEnd);

編集 削除
KHE00221  2013-02-06 10:16:54  No: 43750  IP: 192.*.*.*

var
    StringList: TStringList;
    I: Integer;

    FileHandle: Integer;
    F: TextFile;
    S: String;
begin

    //ダミーデータ作成
    StringList := TStringList.Create;
    for I:=0 to 999 do
    begin
      StringList.Add('_'+IntToStr(12345));
    end;
    StringList.SaveToFile('C:\OLD.TXT');
    StringList.Free;


    FileHandle := FileCreate ('C:\NEW.TXT');
    AssignFile (F,'C:\OLD.TXT');
    Reset (F);
    while not Eof(F) do
    begin
      Readln (F,S);
      FileWrite (FileHandle,S[1],Length(S));
    end;

    CloseFile (F);
    FileClose (FileHandle);

編集 削除
ponta  2013-02-06 20:23:00  No: 43751  IP: 192.*.*.*

take様、ありがとうございます。

>seek(-2,soFromEnd);
やってみましたが現象は変わりませんでした。
Seek(fs.Size-2,soBeginning);と同じ値を取っているようです。

KHE00221様、ありがとうございます。
OLD.TXTは、
_12345
_12345
_12345
・・・
となるのですが、NEW.TXTは
_12345_12345_12345_12345_12345_12345・・・
となってしまいます。要望としては、最後の改行だけを取りたい事でした。

納期が迫ってきてしまい、この現象を修復したいのですが、
別な方法で(手動等)で対処したいと考えています。

take様、KHE00221様ありがとうございました。

編集 削除
KHE00221  2013-02-07 09:56:09  No: 43752  IP: 192.*.*.*

procedure TForm4.Button1Click(Sender: TObject);
var
    StringList: TStringList;
    I: Integer;

    FileHandle: Integer;
    F: TextFile;
    S: AnsiString;
    S2: AnsiString;
    Buffer: array[0..255] of Char;
begin

    //ダミーデータ作成
    StringList := TStringList.Create;
    for I:=0 to 999 do
    begin
      StringList.Add(IntToStr(I) + '_12345');
    end;
    StringList.SaveToFile('C:\OLD.TXT');
    StringList.Free;


    FileHandle := FileCreate ('C:\NEW.TXT');
    AssignFile (F,'C:\OLD.TXT');
    Reset (F);
    while not Eof(F) do
    begin
      Readln (F,S);
      if Eof(F) = False then S := S + #13#10;  // ■ 追加
      FileWrite (FileHandle,S[1],Length(S));
    end;

    CloseFile (F);
    FileClose (FileHandle);

    //先頭のデータが入れ替わるだけでサイズは変わらない
    //FileHandle := FileOpen ('C:\OLD.TXT',fmOpenReadWrite);
    //FileWrite (FileHandle,S[1],Length(S));
    //FileClose (FileHandle);
    //ので新しくファイルを作らないとサイズを小さくする事はたぶん無理
 

end;

編集 削除
ponta  2013-02-07 19:24:50  No: 43753  IP: 192.*.*.*

KHE00221様、ありがとうございます。

> if Eof(F) = False then S := S + #13#10;  // ■ 追加

こんな簡単なロジックをすっかり忘れてました。
試してみたら上手くいきました。
ありがとうございます。

編集 削除