テキストの一番上に追加するセオリーは?

解決


かずま  2008-07-10 23:27:28  No: 31185

すいません、少し調べてみましたが、分からずに困っています。
Appendは、ファイルの最後に追加しますが、それの逆のセオリーはどうするのでしょうか?
自分でも考えたのですが、無駄が多い気がするのと、自信がなくって。^^;
Appendの逆の関数がないみたいですが、もしあったら、バカみたいですし。

ファイルを開く。
1番上に書くのを新規で書き込み。
開いたファイルの内容を、ループして書き込み。

//ファイルを開く
FStrBuf := TStringList.Create;
FStrBuf.LoadFromFile(FileName);

//新規の作成用
Rewrite( fp );

FStrBuf.count-1をループして、追加保存。

ファイル保存の関数を作りたいと思っているので、FileSave('ファイル名','追加する文')としたいので、Memoとかは使いたくないのですが。^^;

セオリーがあれば、ご教授お願い致します。


igy  2008-07-11 00:42:41  No: 31186

TStringList を使って
・LoadFromFile メソッドでファイルを読み込み
・Insert メソッドで、挿入
・SaveToFile メソッドでファイル保存
でどうですか?


かずま  2008-07-11 04:18:49  No: 31187

お目汚しかもしれませんが、一応できたものを公開。
ファイルセーブといえば、成功不成功の戻り値と思って、functionにしたけど、procedureでも問題ないですね。
ファイルの存在チェックを先にやることにしたので、意味がなくなりました。
開けたけど、書き込みない場合は、エラーになるか。x
こちらの方が、私の用途に合っているのと、tryとかがよく分からなかったので。
お尻から何番目、、、という形も考えたのですが、使い勝手が悪いので、やめました。

//===================================================================
//ファイルの保存(自作
//FN,Line : ファイル名、追加書き込み、Inc:挿入場所、-ならお尻に。
//Result:意味がないですね。
//===================================================================
function TForm1.FileSave2(FN,Line:String;Inc:Integer) : Boolean;
var
  FStrBuf  : TStringList;
  F        : TextFile;
begin
  //ファイルチェック
  if not FileExists( FN ) then
  begin
    //空ファイルを作成
    AssignFile(F, FN);
    Rewrite(F);
    CloseFile(F);
  end;

  //ファイルを開く
  FStrBuf := TStringList.Create;
  FStrBuf.LoadFromFile(FN);

  //マイナスの場合は、お尻に
  If Inc < 0 then
    Inc := FStrBuf.Count;

  //ラインの挿入
  FStrBuf.Insert(Inc, Line);
  //ファイルに保存
  FStrBuf.SaveToFile(FN);

  //解放
  FStrBuf.Free;
end;

問題はないと思いますが、「へったくそだなー、もっと簡単になるよ。」という場合は、訂正して頂けると幸いです。
変数の名前の付け方は、ちょっと独特かもしれませんが、独学なのでご容赦くだされ。

もう少し開いておこうかと思います。
とりあえず、igyさんサンクスです。


自分なら・・・  2008-07-11 17:15:10  No: 31188

LoadFromFile の直前にFileExists判定入れるだけでいいのは?

FStrBuf := TStringList.Create;
if FileExists( FN ) then 
  FStrBuf.LoadFromFile(FN);

//ファイルチェック
ここのがAssignFile〜CloseFileが不要になる。


にしの  2008-07-11 19:25:12  No: 31189

こんな感じでどうでしょう。
少し長いです。冗長かも。
大きいファイルを扱う場合や、メモリ使用量が気になる場合には効果があるかと思います。

(**
 * ファイルの先頭に行を追記する。
 * FileName: String  対象ファイルの名前
 * Line: String      追記する文字列。最後の改行はこの関数で必ず付ける
 * IsBackup: Boolean バックアップしたファイルを消すならfalse
 *)
function FileSave(const FileName, Line: String; IsBackup: Boolean): Boolean;
var
  isExistFile: Boolean;
  BackupFileName: String;
  hReadFile: Cardinal;
  hWriteFile: Cardinal;
  Buf: String;
  Len: Cardinal;
begin
  Result := False;
  BackupFileName := ChangeFileExt(FileName, '.BAK');
  isExistFile := FileExists(FileName);
  if FileExists(BackupFileName) then
  begin
    if DeleteFile(BackupFileName) = false then
    begin
      Exit;
    end;
  end;

  hReadFile := INVALID_HANDLE_VALUE;
  if isExistFile then
  begin
    //元のファイルを*.BAKに変更
    if RenameFile(FileName, BackupFileName) = false then
    begin
      Exit;
    end;

    //バックアップしたファイルを開く
    hReadFile := CreateFile(PCHAR(BackupFileName), GENERIC_READ, 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    if hReadFile = INVALID_HANDLE_VALUE then
    begin
      if isExistFile then
      begin
        RenameFile(BackupFileName, FileName);
      end;
      Exit;
    end;
  end;

  //ファイルを開く
  hWriteFile := CreateFile(PCHAR(FileName), GENERIC_WRITE, 0, nil, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
  if hWriteFile = INVALID_HANDLE_VALUE then
  begin
    CloseHandle(hReadFile);
    if isExistFile then
    begin
      RenameFile(BackupFileName, FileName);
    end;
    Exit;
  end;

  //追記分
  Buf := Line + #13#10;
  WriteFile(hWriteFile, PCHAR(Buf)^, Length(Buf), Len, nil);

  //残りをコピー
  SetLength(Buf, 1025);
  if hReadFile <> INVALID_HANDLE_VALUE then
  begin
    while True do
    begin
      ReadFile(hReadFile, PCHAR(Buf)^, 1024, Len, nil);
      if Len = 0 Then Break;
      WriteFile(hWriteFile, PCHAR(Buf)^, Len, Len, nil);
    end;
    CloseHandle(hReadFile); 
  end;

  //閉じる
  CloseHandle(hWriteFile);

  //バックアップがいらないなら消す
  if Not IsBackup then
  begin
    DeleteFile(BackupFileName);
  end;

  Result := True;
end;


かずま  2008-07-11 20:48:08  No: 31190

みなさま、私の様な素人に毛が生えたものに、コメントありがとうございました♪
さらにちょっと手を加えて、追加書き込みしかできなかったので、上書きもできるようにしました。
一応フォルダの存在チェックもするように。

function TForm1.FileSave2(FN,Line,New:String;Inc:Integer) : Boolean;
//パスを絶対パスに
Path := ExpandFileName(FN);
//上書きなら削除
if New = 'On' then DeleteFile(Path);
//フォルダチェック
if not DirectoryExists( ExtractFileDir( Path ) ) then
  MkDir( ExtractFileDir( Path ) );

引数に、Newのon/offを指定して、絶対パスに変換、onなら削除。
フォルダがなかったら、作成です。
削除にがどのタイミングで、次にいくのか分からなかったのですが、1Gのテキストで、onにしても大丈夫だった(たぶん、完全に削除されてから、次の処理に)まぁ、大丈夫なのかなー?と。
本来ならロック処理や別ファイル名にしての方がいいのでしょうが、私レベルではそれ程問題はないだろう、・・・面倒なので、やめました。

PHP育ちなもので、ファイルの読み書きのような、セオリーの書き込みがあるものを、考えるのは少し苦手です。
つい、人のを参考・・・、考えてから丸パクリにしてしまうので。^^;

igy様、自分なら・・・様、にしの様、ありがとうございました。


かずま  2008-07-11 20:51:00  No: 31191

とくに、にしの様のサンプルは大変貴重です。(苦笑
じっくり見てから、使う場面があれば、使わせていたこうかと思います。
やはり、大きなファイルを読み書きする時は、一行ずつの方が、メモリーを食わなさそうですね。
ありがとうございます。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加