質問

特定の宿題として、標準 C でシーケンシャル ファイルを使用する基本的なデータ ストレージ システムを実装していますが、一度に複数のレコードをロードすることはできません。したがって、基本的な部分は、元のレコードに対して実行した結果が保存される新しいファイルを作成することです。以前のファイルの名前が変更され、作業名で新しいファイルが作成されます。コードは Windows 7 上の MinGW 5.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 が削除リクエストか何かでオーバーフローしてクラッシュする可能性があるように思えます。)

役に立ちましたか?

解決

だから、突然、権限のスコットの言及を読んだ後、私は「権限拒否」について考えたと一部のGoogleを適用します。 それはかなり一般的ですが判明、あいまいな場合は、エラーが発生しました。こちら カフェは正しかった、それはコードの別の部分にありました。つまり、私は内容を表示するためのものの関数で同じファイルをfcloseはし忘れていました。私は、その特定の詳細を追跡していなかったので、ランダムであるように思われます。

免責事項:週刊数学assigmentsは非常に少ないスリープ時間のために作ります。 ¬¬

他のヒント

その音は非常に奇妙な、そしてそれ以上に、あなたが同じコードを別のファイル名でOKを動作することを言うとき - 私は強くあなたのコード内の他の場所でバグを疑うでしょう。しかし、あなたが削除したいファイル名を変更して回避することができるようになります。

rename("IndiceNecesidades.old", "IndiceNecesidades.older");
remove("IndiceNecesidades.older");
rename("IndiceNecesidades.dat", "IndiceNecesidades.old");

を確認してみると良いかもしれません remove() エラー時の関数。 man remove 関数が返すと言っています 0 成功と -1 失敗時、設定 errno エラーを記録します。通話を次のように置き換えてみてください

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

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

さらに、削除する必要はないようです

男の名前変更()

rename()システム呼び出しにより、古い名前のリンクが新しいものとして変更されます。新しいものが存在する場合は、まず削除されます。古いものと新しいものは、同じタイプ(つまり、どちらもディレクトリまたは非ディレクトリのいずれかでなければならない)でなければならず、同じファイルシステムに存在する必要があります。

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

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

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

eperm]古いものを含むディレクトリは粘着性とマークされており、含まれるディレクトリも古いものも効果的なユーザーIDが所有していません。

eperm]新しいファイルが存在し、新しいファイルを含むディレクトリは粘着性とマークされており、含まれるディレクトリも新品も有効なユーザーIDが所有していません。

次のステップは、含まれているディレクトリに対するアクセス許可があることを確認することです。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top