DeleteFile(filename)でファイルを削除しようとしてもできないのです。エクスプローラから削除しようとしたら、Windowsメッセージの「共有違反がありました。送り側または受け側のファイルは使用中の可能性があります。」のエラーがでましたので、作成したプログラムを終了させるとエクスプローラからの削除が可能なのです。おそらくこの辺に問題がありそうですが、プログラム上ではキチンとDeleteFile(filename)前にCloseFile(filename);で閉じてます。何故でしょうか?ちなみに削除しようとしているファイルはテキストファイルではなくバイナリファイルです。
削除しようとしているファイルを使用しているプログラムが使っているのではないでしょうか。
「共有違反」には違いないのですが、Windowsがどういう場合をもって、どういう仕組み・手続きで共有違反としているかは、色々調べたのですが、文献が見つかりませんでした。
手がかりをご存知の方があれば私も教えて欲しいと思っています。
WindowsME と Windows2000 以降では扱いが異なり、後者はより厳しくなっています。Windows9x と NT の違いかもしれません。
> プログラム上ではキチンとDeleteFile(filename)前にCloseFile(filename);で閉じてます。
私の経験則では、ファイルに対して共有違反をかけているのではなく、そのファイルが格納されていたディレクトリに対してかかっているようです。
しかし、同じコードでも、時によって削除できる場合とできない場合があったりし、不可解です。
>私の経験則では、ファイルに対して共有違反をかけているのではなく、そのファイルが格納されていたディレクトリに対してかかっているようです。
ファイル単位でファイルのロックはかかります
一度カラのデータを上書きしてからやってみてはいかがでしょうか?
うちのパソコンは消せないときにそうすると消せるようになるので、、
>私の経験則では、ファイルに対して共有違反をかけているのではなく、そのファイルが格納されていたディレクトリに対してかかっているようです。
ファイル単位でロックがかかりますが、ロックのかかったファイルのパスの
フォルダに対しても、結果としてロックがかかるような状態になるため
(フォルダ名を変えたり、フォルダを削除したりできない)、このような
表現になったのではないでしょうか。
本スレの内容から離れてすいません。
皆様ありがとうございます。しかし解決しないのです。
ファイルのロック・・・とありますが、このロックを外す方法はあるのでしょうか?
ちなみに、私のやりたいことは、『①新規にBのファイルを作成→②Aのファイルの内容をBにコピーする→③Aのファイルを削除する→④Bのファイル名をAのファイル名に変更する。』ということをやろうとしているのですが、③のファイル削除ができないためと思いますが当然④のファイル名変更もできないのです。このファイルは全て同じフォルダ上にあるものです。
その現象を検証できる必要最小限のコードを示すべきでしょう。
処理の内容は意味不明ですが、以下のようでしょうか?
var
slB: TStringList;
begin
//①新規にBのファイルを作成
slB := TStringList.Create;
try
slB.SaveToFile('C:\Temp\B.txt');
finally
slB.Free;
end;
//②Aのファイルの内容をBにコピーする
CopyFile(PChar('C:\Temp\A.txt'), PChar('C:\Temp\B.txt'), False);
//③Aのファイルを削除する
DeleteFile('C:\Temp\A.txt');
//④Bのファイル名をAのファイル名に変更する
MoveFile(PChar('C:\Temp\B.txt'), PChar('C:\Temp\A.txt'));
end;
>『①新規にBのファイルを作成→②Aのファイルの内容をBにコピーする→③
> Aのファイルを削除する→④Bのファイル名をAのファイル名に変更する。』
考え方を変えて、以下はどうでしょう?
(1)Aファイルを別名に変更する(すでに別名があれば削除か上書き)
(2)新規Bファイルを、Aファイルの元の名前で作成する
(3)Aのファイルの内容をBにコピーする
(4)Aファイルを削除する
(4)が失敗しても、正式ファイル名の内容は正しいものです。
そうじゃなければ・・・
AssignFile の回数と、CloseFile の回数合ってないとか、
CLoseFileの前に、おまじないで「Sleep(10);」を入れてみるとか・・・。
新規ファイルの作成方法にもいくつかあります。
ようやく時間が取れたので、①から④を TFileStream を使って試してみました。
環境 Windows2000 Del7Pro
しかし、何も問題は起きませんでした。
deldel さんが例示して下さったような方式で、
削除できない再現コードを示していただくしかないでしょう。
また、既に触れられていることですが、
「Aファイル」は、、①から④を行うアプリとはどのような関係にあるアプリで作成されたものでしょうか。Word などのような有名なソフトなら名称を開示したほうが早いでしょう。
また、その作成したアプリはAファイル作成後①から④を行う場合にはまだアクティブなのか終了しているのかも関係してきます。
尚、フォルダに関する私の発言は、せそ さんの推測どおりです。
//旧ファイルの内容を新規ファイルに移す。
procedure CopyIndexData(kisyu:String; NewKibanMin:Integer; NewKibanMax:Integer);
var
OldData: VistaAdmin.TForm1.VistaIndexFormat;//レコード型
NewData: VistaAdmin.TForm1.VistaIndexFormat;
OldIndexFileP: File of VistaAdmin.TForm1.VistaIndexFormat; //型付きファイルの宣言
NewIndexFileP: File of VistaAdmin.TForm1.VistaIndexFormat;
OldIndexFName: String; //Index
NewIndexFName: String; //NewIndex
RecPos: Integer;
begin
OldIndexFName:= VistaAdmin.TForm1.VistaDataFolder +kisyu+ '\Index';
NewIndexFName:= VistaAdmin.TForm1.VistaDataFolder +kisyu+ '\NewIndex'; //他のprocedureの中で、既に新規作成しデフォルト値を入れてる。
AssignFile(OldIndexFileP, OldIndexFName);
AssignFile(NewIndexFileP, NewIndexFName);
Reset(OldIndexFileP);
Reset(NewIndexFileP);
while not Eof(OldIndexFileP) do begin
Read(OldIndexFileP, OldData);
RecPos:= OldData.Kiban - NewKibanMin; //登録するレコード番号を算出
Seek(NewIndexFileP, RecPos);
Read(NewIndexFileP, NewData); //念のため、NewIndexとIndexに記録されている機番を照合する
if NewData.Kiban=OldData.Kiban then begin //OKならばNewIndexにOldDataの内容を記録し、違えばエラーとし中断
Seek(NewIndexFileP, RecPos);
Write(NewIndexFileP, OldData);
end
else begin
// NewData.Kiban=OldData.Kibanでなかった場合の処理
Exit;
end;
end;
CloseFile(OldIndexFileP);
CloseFile(NewIndexFileP);
ShowMessage('転記完了');
//DeleteFile RenameFile ができない。 なぜでしょう?
if DeleteFile(OldIndexFName) then ShowMessage('旧インデックス(Index)を削除しました。') //Indexを削除
else ShowMessage('失敗!! 旧インデックス(Index)の削除に失敗しました。'+#10+'プログラム終了後に削除してください。');
if RenameFile(NewIndexFName, OldIndexFName) then ShowMessage('NewIndexをIndexにファイル名変更しました。') // NewIndexをIndexに変更
else ShowMessage('失敗!! ファイル名の変更に失敗しました。'+#10+'NewIndexをIndexにファイル名変更してください。');
end;
コードは以上ですが、別途簡単なプログラムの中でおこなうと問題無く、削除、ファイル名変更ができました。何が問題なのでしょうか? 益々分らなくなってきました。 よろしくお願いします。
> else begin
> // NewData.Kiban=OldData.Kibanでなかった場合の処理>
> Exit;
> end;
ここがダメね。
全くダメな貴兄さんへ。
すみません。その部分は省略して書いたのです。デバックして確認してますが、この部分は通ってません。間違いなくCloseFileして if DeleteFile(OldIndexFName) then ShowMessage・・・・・・の行を実行してます。
コードについては意見がありますが、
掲載されたコードの範囲では問題ないように見えますので、触れません。
で、OldIndexFName はいつどこでどのように作成されているのでしょう。
DeleteFile で OldIndexFName が削除できない場合はご存知の通り次のケースです。
1.存在しない。(これは今回ありえない)
2.「アプリケーションがオープンされたファイル」である。(NTの場合のみ)
この意味は日本語として理解できませんが、他のアプリあるいはプロセスにより開いたままになっている、と解しています。
3.他のアプリあるいはプロセスによりメモリマップされている。(NTの場合のみ)
4.FileMode を fmOpenRead でわざわざ指定した。(これも今回はありえない)
5.ファイル属性が ReadOnly になっている。そうであれば、例外メッセージが出るはず。
6.その他の何らかの原因。これは、5までの可能性が完全消去された場合に検討。
いずれにせよ「別途簡単なプログラムの中でおこなうと問題無く、削除、ファイル名変更ができました。」ということですから、解決は既にあなたの手の内にあります。
「益々分らなくなってきました。」というときの常套手段は、「問題なくできたコード」に、一つ一つあなたがすでに追加しているコードを加えていってどの段階でできなくなるかを確かめることです。
こういう場合、難しいところではなく、きわめて初歩的な部分でのミスが多いものです。それだけに発見しにくい。
「省略して書いた」ということなので触れませんでしたが、気になるので追伸です。
貴兄さんの指摘は大切な点で、
1.Exit ではなく Break を使用する。
そうしないと、ここを通った場合CloseFileが実行されず重大なバグになります。
2.それとは関係なく、CloseFile のような処理を必要とする場合には
AssignFile();
try
finally
CloseFile();
end;
のように必ず実行されるようにします。
色々とありがとうございました。
ご指摘どおり再度ひとつひとつ確認してみようと思います。
なお、「コードについては意見がありますが、・・・」とありましたが、できればコードに対する意見も言っていただければ幸いです。高齢故に頭がついていけないかもしれませんが。。。 よろしくお願いします。
私よりご高齢かどうか解りませんが、お仲間が見つかり嬉しい限りです。
コードの内容というより、こういう場合のテストコードとしては、新たなプロジェクトを起こし、型付ファイルとレコードの定義も簡単なものを設定するなど、問題の本質を絞った簡潔で解りやすいコードを書き下ろしたほうが良いかと。
第3者の意見を求めるにもそのほうが検討しやすいですし。
あなたの書かれたコードだと、余程余裕があるときしか検討する気になれません。
投稿するときの礼儀というよりも、そういう余分な手間をわざわざかけることが自身の向上につながると思います。
回答される人の多くも、自身で使用することがないであろうコードをわざわざ書いて試した上で対応していると思います。
それもやはり、別に質問者のためではなく、自身の向上のためが多いでしょう。
皆様大変お手数をお掛けして申し訳ありませんでした。
他の手続きの中で同じファイルをOpenしたままであったのが発見されました。
sadoyamaさんの言われたとおり、全く初歩的なミスでした。
ありがとうございました。
ツイート | ![]() |