お世話になっております。
ファイルの中の末尾 #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;
環境を書くのを忘れました。
WindowsXP,Delphi7 です。
テキストエディタで適当に書いてみたので試していませんが
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 を使えば
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; にしても同様に違う文字が取得されます。
何かオーバーフローとか、間違いを起こしているのでしょうか。
気づいた所がありましたら、教えて頂けますか?
seekが取り得る値が-2147483648..2147483647 ですので
2Gバイト以上だと処理できないかもしれません。
(Delphi7での話)
末尾から指定するというやりかたではどうでしょうか?
seek(-2,soFromEnd);
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);
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様ありがとうございました。
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;
KHE00221様、ありがとうございます。
> if Eof(F) = False then S := S + #13#10; // ■ 追加
こんな簡単なロジックをすっかり忘れてました。
試してみたら上手くいきました。
ありがとうございます。