- PR -

プロセスが握っているディレクトリの強制排除

投稿者投稿内容
ほったて
ベテラン
会議室デビュー日: 2007/11/10
投稿数: 68
投稿日時: 2009-02-21 10:07
なんかいっぱい書き込みがあるなあと思ってたら、

引用:

未記入さんの書き込み (2009-02-19 20:24) より:

//フォルダの存在チェック(無ければ作成する)
if (System.IO.File.Exists("C:/tmp" + "/back") == false){
System.IO.Directory.CreateDirectory("C:/tmp" + "/back");
}

//出力先PDFファイル名作成
_outputfile = "C:/tmp" + "/back" + "/test.pdf";

//PDFファイル移動
File.Move(realfile, _outputfile);



プログラムの中で対処したかったんですね。
気づかなかったよ (´・ω・`) シャボーン

もうしわけないです。
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2009-02-21 13:35
引用:

未記入さんの書き込み (2009-02-20 10:24) より:
>Jittaさん
C#はほとんど初心者なのですが、ワーキングディレクトリとはどのような事を指しているのでしょうか?.netが内部的に一時ディレクトリを使っていると言う事でしょうか?また、削除するのに属性をチェックしないといけないのでしょうか?

getTempPathでこのように取れたのですが・・。
C:Documents and SettingsLocalServiceLocal SettingsTemp

カレントディレクトリなど、Javaでは意識した事ないんですが・・(UNIX系はありますけど)。
MS製品の仕様と言うことでしょうか?


プロセスでファイルを扱う場合に、絶対パスを指定しない時があります。それでもファイルにアクセスできるのは、プロセスがどこかのディレクトリをワーキングディレクトリとして押さえているからです。これは、System.IO.Directory.GetCurrentDirectory メソッドで確認できます。

将来的に、C ドライブに書き込みができるか、C ドライブがあるか、保障されません。一時ファイルの置き場所は、System.IO.Path.GetTempPath メソッドで取得します。
コード:
#using System.IO


string work_dir = Path.Combine(Path.GetTempPath(), "PDF_test"); 
foreach (string fName in Directory.GetDirectories(work_dir)) { 
    foreach (string fileName in Directory.GetFiles(fName)) { 
        string bk = Path.Combine(pdfback_dir, Path.GetFileName(fName));
        if (Directory.Exists(bk) == false) { 
            Directory.CreateDirectory(bk); 
        } 
        bk = Path.Combine(bk,  Path.GetFileName(fileName)); 
        if (File.Exists(bk) == true) { 
            File.Delete(bk); 
        } 
        File.Copy(fileName, bk); 
        File.Delete(fileName); 
    } 
    // ここで、現在のディレクトリを表示させてみる
    MessageBox.Show(Directory.GetCurrentDirectory);
    Directory.Delete(fName, true); ←ここで、以下のエラーが出てます。 
} 



同じように、もう一つの、作るほうのスレッドも、作り終わった時点でどこにいるのか、表示させてみてください。
最初に、SaveFileDialog などで、ディレクトリを選んでいないでしょうか?もしそうなら、RRestoreDirectory プロパティ<microsoft.com> を true にすれば、解決できるかもしれません。
未記入
大ベテラン
会議室デビュー日: 2008/07/11
投稿数: 182
投稿日時: 2009-02-21 16:59
ご回答ありがとうございます。はまってます・・。


教えていただいたようにパスを調べました。下記が両処理部のソースですが、
両方とも@の前後で確認しました。
Directory.GetCurrentDirectory(); "C:\\WINDOWS\\system32"
Path.GetTempPath(); "C:\\Documents and Settings\\LocalService\\Local Settings\\Temp\\"

ですが、全てこの値に変わりませんでした・・。
元々、Java上がりでして、カレントを移すというような発想もありませんでして・・。
他の部分も意図的に変えていないと思います。

●生成部(Thread1)
//フォルダの存在チェック(無ければ作成する)
if (System.IO.File.Exists("C:/tmp" + "/back") == false){
System.IO.Directory.CreateDirectory("C:/tmp" + "/back");
}
//出力先PDFファイル名作成
_outputfile = "C:/tmp" + "/back" + "/test.pdf";
//PDFファイル移動
File.Move(realfile, _outputfile); ←@両方ともフルパス指定

●バックアップ処理部(Thread2)
string work_dir = Path.Combine(Path.GetTempPath(), "PDF_test");
foreach (string fName in Directory.GetDirectories(work_dir)) {
foreach (string fileName in Directory.GetFiles(fName)) {
string bk = Path.Combine(pdfback_dir, Path.GetFileName(fName));
if (Directory.Exists(bk) == false) {
Directory.CreateDirectory(bk);
}
bk = Path.Combine(bk, Path.GetFileName(fileName));
if (File.Exists(bk) == true) {
File.Delete(bk);
}
File.Copy(fileName, bk);
File.Delete(fileName);
}
// ここで、現在のディレクトリを表示させてみる
MessageBox.Show(Directory.GetCurrentDirectory);
Directory.Delete(fName, true); ←ここで、以下のエラーが出てます。 @
}


ちなみに生成部で、ファイル作成後このディレクトリを削除しました所、正常に削除されました。
やはり、Threadが原因の削除不可が起きてる気がするのですが・・。

また、Javaですと、ディレクトリの保持、streamの開放漏れなど、ファイル・ディレクトリ操作ではありますが、C#は全てフルパスの文字列なんですよね(私の場合のみかもしれませんが・・)。
ソースで対応しようにも糸口が見つからない状態です・・。

また、どこかお気付きになりましたら、どうぞよろしくお願いします。

>ほったてさん
教えていただきありがとうございます。他ツールのインストールはちょっと考えてませんでした。
最悪、batでもできる事ですし。不思議なのはエクスプローラからは削除できるんですがね・・。このアプリが稼動中でも・・。??
ぽぴ王子
ぬし
会議室デビュー日: 2006/03/24
投稿数: 475
お住まい・勤務地: お住まい:城・勤務地:城
投稿日時: 2009-02-22 11:08
まずは、情報を正しく伝えることが大事だと思います。

引用:

未記入さんの書き込み (2009-02-19 18:36) より:

現在、C#のプログラムで、ディレクトリのバックアップをしているのですが、そのディレクトリは同じプログラム内ですが、別Threadが握っています。


この時点で「同じプログラムの別のスレッドでコピーと削除をしている」という意図を読むのは少々無理があったかもしれません。
件名も「プロセスが握っているディレクトリの強制排除」なのもあり、私は「別Thread」は「別のプログラム」と読みました。

別のプロセスではなく、別のスレッドでコピーと削除を行っているという話が正しく言及されたのは以下の投稿だと思います。

引用:

未記入さんの書き込み (2009-02-21 16:59) より:

ちなみに生成部で、ファイル作成後このディレクトリを削除しました所、正常に削除されました。
やはり、Threadが原因の削除不可が起きてる気がするのですが・・。


原因を推測すると、削除スレッドが削除を行う前にコピースレッドがディレクトリを使用している可能性があるため、削除できないのではないかと思います。ただ、そこに行き着くまでの流れが曖昧だったのでいろいろな提案がなされたのだと思います。

こちらのスレッドで、ぴあちゃんさんに指摘を受けていますが、それが生かされていないようです。

引用:

ぴあちゃんさんの書き込み (2008-10-28 01:26) より:

なんでもかんでも掲示板に問い合わせてはいけません。
また、自分勝手な思い込みで事実を捻じ曲げて情報を小出しにするのも良く無いです。
今回の場合だと、最初に
TEST="20" />
ってやっておいて、後から、
<APP X="10" Y="20" TEST="10" />
ってだんだん表現が大きくなってるし。一杯入れた修正のひとつでたまたまエラー箇
所がそこだった(本当のエラーは別の場所)ってだけかもしれません。

思わせぶりというか、客寄せじゃないのだから、もっと正確で詳細な情報を載せれば
より的確なアドバイスが得られるでしょう。問答自体が時間の無駄ですよ、きっと。


こちらのスレッドはこれで投稿が止まっていますが、解決されたのでしょうか。スレッドを放置して他の質問をするのはあまり良いとは思えません。
_________________
ぽぴ王子@わんくま同盟
ぽぴ王子の人生プログラミング中 / ぽぴンち。
未記入
大ベテラン
会議室デビュー日: 2008/07/11
投稿数: 182
投稿日時: 2009-02-22 19:34
>ぽぴ王子さん

ありがとうございます。
表現が悪く、申し訳ありませんでした。過去質問したお題についても、忘れていました。
もうしわけありませんでした。

また、「プロセスが握っているディレクトリの強制排除 」をソース上で実現できるのかも分からない状態ですが、こちらは可能でしょうか?

Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2009-02-22 21:44
引用:

foreach (string fName in System.IO.Directory.GetDirectories(work_dir)) {


ここ、次のようにしてみたら、どうなります?

コード:
string[] dNames = Directory.GetDirectories(work_dir);
for (int i = 0; i < dNames.Length; ++i) {

未記入
大ベテラン
会議室デビュー日: 2008/07/11
投稿数: 182
投稿日時: 2009-02-22 23:29
ありがとうございます。

教えていただいたようにしてみたのですが、現象は同じでした。

どうも、Threadが自身で生成したディレクトリを暗黙的に保持しているように感じます。
と言いますのも、前述の「●生成部(Thread1)」内でこのディレクトリをインターバルを介して、削除を行うとすんなりできました。
特に、属性を変更したり、カレントディレクトリを再セットしていません。

そうしますとこのプログラムが動作している上で、エクスプローラ上で削除できると言う現象が説明できませんが・・。
(Windowsが握っているのでは無く、.netFrameworkが握っている?)

これで、「●バックアップ処理部(Thread2)」はファイルの移動だけ、「●生成部(Thread1)」の前で、ファイルが一枚も無い場合にそのディレクトリは削除と言うようにすれば解決はできそうです。

ただ、Thread内で生成したディレクトリは、他ディレクトリでは削除できないと言うことになりますと、今後も問題が出てきそうなので、同じような仕様経験があり、その時の現象・対処法を教えていただけるとありがたいです。
(ちなみに生成したファイルはバックアップ処理(別プロセス)で削除できてるんですが・・。)

・同アプリ内で複数Threadを使い、ディレクトリ操作を行っている。
・それぞれ別Threadで同じディレクトリに対し、作成・削除を行っている。


[ メッセージ編集済み 編集者: 未記入 編集日時 2009-02-23 10:22 ]
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2009-02-24 12:22
それでは、それぞれのスレッドが実際に作業を行っている期間が重なっていないか、確認してみてください。

File.Move 中にディレクトリが消されたら、まずいですよね?

# realfile から直接 pdfback_dir へコピーしたら良いんじゃない?

スキルアップ/キャリアアップ(JOB@IT)