1

特定の宿題については、標準Cでシーケンシャルファイルを使用する基本的なデータストレージシステムを実装しています。これは、一度に複数のレコードをロードすることはできません。したがって、基本的な部分は、元のレコードで行ったすべての結果が保存される新しいファイルを作成することです。以前のファイルの名前が変更され、作業名で新しいファイルが作成されます。コードは、Windows7のMinGW5.1.6でコンパイルされています。

問題は、この特定のバージョンのコード(ほぼ同じバージョンのコードが関数の周りに浮かんでいる)が常に古いファイルを削除するとは限らないため、名前の変更が失敗し、保存されたデータがfopen()によって消去されることです。 。

FILE *archivo, *antiguo;

remove("IndiceNecesidades.old");  // This randomly fails to work in time.
rename("IndiceNecesidades.dat", "IndiceNecesidades.old"); // So rename() fails.

antiguo = fopen("IndiceNecesidades.old", "rb");
// But apparently it still gets deleted, since this turns out null (and I never find the .old in my working folder after the program's done).
archivo = fopen("IndiceNecesidades.dat", "wb"); // And here the data gets wiped.

基本的に、.oldが以前に存在する場合は常に、rename()が正常に有効になるのに間に合うように削除されない可能性があります。内部と外部の両方で名前が競合する可能性はありません。

奇妙なことは、それがこの特定のファイルだけにあるということです。名前がNecesidades.dat(3つの異なる関数で発生)に変更されていることを除いて、同一のスニペットは完全に正常に機能します。

// I'm yet to see this snippet fail.
FILE *antiguo, *archivo;

remove("Necesidades.old");
rename("Necesidades.dat", "Necesidades.old");

antiguo = fopen("Necesidades.old", "rb");
archivo = fopen("Necesidades.dat", "wb");

なぜこれが発生するのか、および/またはrename()が実行されるまでにremove()コマンドが有効になっていることを確認するにはどうすればよいですか?(fopen()がnull以外のポインターを返す限り、whileループを使用してremove()の呼び出しを再度強制することを考えましたが、削除要求などでOSがオーバーフローしたためにクラッシュを懇願するように聞こえます。)

4

3 に答える 3

3

それで突然、スコットの許可についての言及を読んだ後、私は「許可が拒否されました」について考え、いくつかのグーグルを適用しました。あいまいな場合でも、かなり一般的なエラーであることが判明しました。 cafは正しかった、それは別のコードにあった。つまり、内容を表示するための関数で同じファイルを閉じるのを忘れていました。私はその特定の詳細を追跡していなかったので、それはランダムに見えました。

免責事項:毎週の数学の割り当ては、ほとんど睡眠時間を作りません。¬¬

于 2010-04-13T04:36:19.547 に答える
1

remove()関数にエラーがないか確認することをお勧めします。関数が成功時と失敗時にman remove戻り、エラーを記録するように設定していることを示します。通話を次のように置き換えてみてください0-1errno

if (remove("IndiceNecesidades.old") != 0){
   perror("remove(\"IndiceNecesidades.old\") failed");
}

何が失敗したかを示すエラーメッセージが表示されます。

さらに、削除が必要なようには見えません

man rename()

rename()システムコールにより、oldという名前のリンクの名前がnewに変更されます。newが存在する場合は、最初に削除されます。古いものと新しいものの両方が同じタイプである必要があり(つまり、両方がディレクトリまたは非ディレクトリのいずれかである必要があります)、同じファイルシステム上に存在する必要があります。

rename()システムコールは、システムが操作の途中でクラッシュした場合でも、newのインスタンスが常に存在することを保証します。

oldの最後のコンポーネントがシンボリックリンクである場合、シンボリックリンクは、それが指すファイルまたはディレクトリではなく、名前が変更されます。

EPERMは、次の場合に返されます。

[EPERM] oldを含むディレクトリはスティッキーとマークされており、含むディレクトリもoldも実効ユーザーIDによって所有されていません。

[EPERM]新しいファイルが存在し、newを含むディレクトリはスティッキーとマークされており、含まれているディレクトリもnewも有効なユーザーIDによって所有されていません。

したがって、次のステップは、含まれているディレクトリに対する権限があることを確認することです。

于 2010-04-13T03:37:37.193 に答える
1

それは非常に奇妙に聞こえますが、同じコードが別のファイル名で正常に機能すると言うと、コードの他の場所にバグがあると強く疑われます。ただし、削除するファイルの名前を変更することで、この問題を回避できるはずです。

rename("IndiceNecesidades.old", "IndiceNecesidades.older");
remove("IndiceNecesidades.older");
rename("IndiceNecesidades.dat", "IndiceNecesidades.old");
于 2010-04-13T03:45:48.777 に答える