2

一時ファイルに書き直して元のファイルを上書きして編集したいテキストファイルがあります。このコードは単純化されているのでそれをしませんが、私が抱えている問題が含まれています。Windowsでは、名前変更機能が失敗すると、一見ランダムな回数の実行後に、EXAMPLE.TXTファイルが表示されなくなります。理由はわかりませんが、これまでのところLinuxでは問題なく動作しています。なぜこれが発生するのですか?また、名前を変更せずにプログラム内から元のファイルを上書きするなど、まったく異なる方向に進むことをどのように解決できますか?

さらに、他にどのようなより良い方法がありますか?このメソッドには、removeが呼び出された直後、名前を変更する前にユーザーがプログラムを閉じるなど、Windowsに他の欠陥があります。これは、Linuxでは問題になりません(removeを削除した後)。

#include <stdio.h>
#include <assert.h>

int main(int argc, char *argv[]) {
  unsigned int i=0;
  FILE *fileStream, *tempStream;
  char fileName[] = "EXAMPLE.TXT";
  char *tempName = tmpnam(NULL);

  while(1) {
     printf("%u\n",i++);
     assert(fileStream = fopen(fileName, "r+"));
     assert(tempStream = fopen(tempName, "w"));

     fprintf(tempStream,"LINE\n");
     fflush(tempStream); /* fclose alone is enough on linux, but windows will sometimes not fully flush when closing! */

     assert(fclose(tempStream) == 0);
     assert(fclose(fileStream) == 0);
     assert(remove(fileName) == 0); /* windows fails if the file already exists, linux overwrites */
     assert(rename(tempName,fileName) == 0);
  }
}
4

2 に答える 2

5

このようにすると、確かにトラブルが発生する可能性があります。Windows でコードを実行すると、次の 4 つの結果が生じる可能性があります。

  • 正常に削除され、名前の変更が機能し、問題ありません
  • 削除は問題ありませんが、別のプロセスが削除共有でファイルを開いていました。マルウェア スキャナーとファイル コンテンツ インデクサーで一般的です。これにより、ファイルの最後のハンドルが閉じられたときに、ファイルが実際に削除されることが保証されます。問題は、ファイルがまだ存在するために名前の変更が失敗することです
  • ファイルがロックされているため削除されず、アサートが発生します
  • リリース バージョンをビルドするときに assert() はノーオペレーションであるため、何も起こりません。

ところで、最後の弾丸の良いオッズ、それは確かに繰り返し可能な失敗を説明しています. 2 番目の弾丸に対処するには、より防御的な戦略が必要になります。

  • filename.bak を削除し、失敗した場合はエラーを報告します
  • fileName の名前を filename.bak に変更し、失敗した場合はエラーを報告します
  • tempName の名前を filename に変更し、エラーを報告し、失敗した場合は filename.back の名前を元に戻します
  • filename.bak を削除し、エラーを報告しない

これはよくあるシナリオで、winapi にはそのための関数ReplaceFile()があります。費用対効果を最大限に高めるために、必ずバックアップ ファイル オプションを使用してください。-

于 2012-06-13T20:49:38.163 に答える
1

ウイルス対策ソフトウェアは、都合の悪いときにファイルをスキャンすることで、このような問題を引き起こすことがあります。

失敗した場合はremove、短時間スリープしてから再試行してください。

于 2012-06-13T19:32:06.797 に答える