- ベストアンサー
FTPで書き込み中のファイルの完了を知りたい
FTPで書き込み中のファイルがあるとします。そのファイルが、書き込み中なのか、それとも、書き込みが完了したのかを、知りたいのですが、良い方法はありますでしょうか。書き込みファイル名はあらかじめ、わかっています。(書き込み中に読んだ場合、最後まで読み切ることが出来ないために書き込み完了迄待ちます)当方で、調査した限りでは、ファイル名を指定して、そのファイルが、他プロセスによってオープンされているか否かを知るシステムコールは存在しませんでした。OSは、sun solaris10を使用の予定ですが、UNIX系(linux含む)で実現可能であれば、かまいません。
- みんなの回答 (13)
- 専門家の回答
質問者が選んだベストアンサー
一般のUnix系のOSで、fopen() でチェックできるかどうかは疑問です^^ たしかに、Unix系のOSで、ファイルをオープンしているプロセスがあるかどうかを調べられるような標準的なシステムコールがあるという話は、あまり聞かないですよね。 http://www.mlb.co.jp/linux/mld-ml/200206/msg00028.html ←存在しないのがほんとに真実かどうかは知りませんが^^ ftp の際、get してくるファイルのサイズ情報をどこかに出力しておいて、そのサイズに達したか否かで、「書き込み中か、書き込み完了か」を判定するのがもっともポータブルな方法かと^^ ※ 最初に lseek などして、見掛けのサイズを大きくしておいてから rewind して実際に書き込みを始めるみたいなことしてる ftp の実装なんてあるとまずいですけど^^;
その他の回答 (12)
- R32C
- ベストアンサー率39% (115/290)
xferlog とか サーバーログの確認では、だめなのでしょうか?
お礼
回答ありがとうございました。ちょっと、期待していた回答ではないのですが「サーバーログの確認」ということで、参考になりました。
- mikaemi
- ベストアンサー率50% (33/65)
> 運用上、上記の短所が問題にならなければ、採用の候補… あはは。ありがとうございます(笑)まぁ、人間、自分のアイデアを大事にしたいというのが普通ですから^^ ここは、議論の場ではないようですが、色々とアイデアを出し合うのは楽しいですね。ではでは、お邪魔しました^^ ==== // ディレクトリから fname にファイル名を得る … char *p = strrchr(fname, '_'); if (p == NULL) return; // 約束違反のファイル名 char *q = strrchr(fname, '.'); if (q == NULL || q < p) return; // 約束違反のファイル名 *q = '\0'; size_t fsiz = atol(p + 1); if (fsiz == 0) return; // サイズ0はおかしい(笑) … *q = '.'; stat(fname, &statbuf); if (statbuf.st_size != fsiz) return; // 書き込み中? … === # .netrc が適当に設定されているとして … fname=`basename $pathname` fsiz=`ls -l $file | awk '{print $5}'` remotefile=`echo $fname | sed -e "s/\\([^.]*\\)\\.\\([^.]*\\)/\\1_$fsiz\\2/"` ftp $remotehost <<EOF bin put $pathname $remotefile bye EOF === とか、やればいいんじゃないですか?^^ 修正時刻のチェックは、エラー処理に活用できますね(現在時刻と最終修正時刻の差があまりに大きいにもかかわらず、サイズが異なる場合など)。
お礼
ソースまで提示していただき、ありがとうございます。mikaemi様の案が採用となった暁には、是非このソースも参考にさせていただきます。
- zwi
- ベストアンサー率56% (730/1282)
もう一案。 手元にcygwinしかないので確認できないのですが。 まず実験として、 (1)pfilesコマンドでFTPデーモンのファイルディスクリプタ一覧を得る。 (2)ファイルディスクリプタ一覧のinode番号で、目的とするファイルが使用中か確認する。目的のファイルのinode番号はstatで得ておく。 なんてのはどうでしょうか? pfilesコマンド自体の機能もソース見ればわかると思うので、プログラム上に吸収可能だと思います。
お礼
回答ありがとうございます。いくつかの理由があって、たぶん、この方法を採用することは、無いとおもいますが、デーモンが「特定のファイルを書き込み中」か否かを判断する方法としては、最もこの案が、正解に近いと思います。又、pfilesコマンドの存在について判っただけでも収穫でした。ありがとうございました。
- mikaemi
- ベストアンサー率50% (33/65)
なるほど。。修正時刻のチェックしてもいいですね。各人各様で思いつくテクニックが異なっておもしろいですね^^ そういえば、ファイル名にファイルサイズを入れるとしても、バイナリモードで転送しないと、Windows⇔Unix⇔Macintoshなんかは、サイズが変わってしまいますねぇ。まぁ、でも、バイナリで転送するとして、stat()・lstat() を使うなら読み続けなくても、ファイルが置かれるディレクトリを舐めて、各ファイルの名前から取得したファイルサイズとstat()が返すファイルサイズをチェックするだけでいいですね^^
お礼
回答ありがとうございます。 >バイナリで転送するとして、stat()・lstat() を使うなら読み続けなくても、ファイルが置かれるディレクトリを舐めて、各ファイルの名前から取得したファイルサイズとstat()が返すファイルサイズをチェックするだけでいいですね^^ 上記の場合の長所と短所は以下になるかと思います。 長所:statが一回ですむ。 短所:FTP送信側での処理が多少発生する。 受信側でもファイル名にファイルサイズを含むため、ファイル名が固定にならずに、XXXXX_nnnnnn(nnnnnはファイルサイズ)にマッチするようなファイルを取得する必要がある。 運用上、上記の短所が問題にならなければ、採用の候補として検討したいと考えています。
- zwi
- ベストアンサー率56% (730/1282)
すごく大雑把な方法ですが、statで最終修正時刻を調べて一定時間以上変更がなかったら書き込みが終了とみなすのはだめでしょうか? 信頼性と即時応答性は限りなく低いですが。
お礼
回答ありがとうございます。 >すごく大雑把な方法ですが、statで最終修正時刻を調べて一定時間以上変更がなかったら書き込みが終了とみなすのはだめでしょうか? その方法と同じではないですがstatでファイルサイズを調べて、一定時間経過後、前回と同じなら、書き込み完了とみなす。 ということは、考えておりました。 statで調査する場合は以下の長所/短所になるかと思います。 長所:FTPの送信側によけいな処理をさせないで済む。 短所:>>「信頼性と即時応答性は限りなく低いですが。」 運用上、上記の短所が問題にならなければ、statを繰り返す方法もありかと考えております。
- mikaemi
- ベストアンサー率50% (33/65)
で、あとは、受け手側は、ファイル名に含まれるバイトサイズを信用して、そのバイトサイズに達するまで読み続ける。エラー処理が難しいですかね^^;
- mikaemi
- ベストアンサー率50% (33/65)
それでは、ファイル名に、ファイルサイズを含めれば簡単じゃないですかね。ファイル名の長さに余裕があるシステムだと仮定して、たとえば、123456Byte なら、filename_123456.txt とか^^ 安易すぎるかな(笑)
- mikaemi
- ベストアンサー率50% (33/65)
あぁ、なるど。。。送り手側が、別マシンから受け手側のマシンに ftp でファイルを put しにくるわけですか。。「ssh などを使わないので、リモートでコマンド実行できるわけではないため、受け手側はファイルが置かれたかポーリングはするが、書き込みが終了しているかを確認する手軽な手段が欲しかった」というわけですね。
お礼
はい、まさに、その通りです。「受け手側はファイルが置かれたかポーリングはするが、書き込みが終了しているかを確認する手軽な手段」を実現するシステムコールがあればと思って、質問した次第です。
- mikaemi
- ベストアンサー率50% (33/65)
あぁ、あと、ftp をプログラム内から fork()・exec() させてるなら、wait() したり、ほかに仕事があるなら waitpid() したり、 SIGCHILD をうけとるようにしたりする方法もありますね^^ tatsu99 さんは、詳しそうなのでご存知でしょうが^^ 蛇足として。。。(笑)
お礼
ファイルの送信側は、シェルスクリプトからftpコマンドを呼びだすことを、今は、考えています。ですので、あまり複雑なことは、出来ません。また、送信側にあまり、コストをかける訳にもいかないので、シェルから呼び出す程度になるかと思います。まあ、送信時のエラー検知ぐらいは、したほうが良いと考えていますが・・・。
- mikaemi
- ベストアンサー率50% (33/65)
あぁ。。すみません^^ ファイルをコピーするのか勘違いしてました^^; link()、unlink() を使ってやるなら大丈夫そうですね。
- 1
- 2
お礼
ご回答ありがとうございます。やはり、無いと考えたほうが、良さそうでね。求めるシステムコールが、存在しない場合の対策案は、私のほうで、2、3検討済みです。 1案:対象ファイル送信後に、送信完了を示す、別なファイル(サイズ:0)をおくる。読み込み側は、サイズ:0のファイルの出現で、目的ファイルの送信完了を判定。 2案:対象ファイルを別の一時的な名前で書き込み、完了後に正規の名前にリネームする。リネームされて、求めるファイルが出現したときは、既に書き込みが完了されたファイルとなっている。 3案:実際のファイルの内容の最後に、ファイル終端であることを示す、あらかじめ決められた特定の文字列を書き込む。読み込み側は、その文字列まで読めれば、書き込みが完了したファイルと判定する。 などの方法がありますが、いずれもFTPの送信側(書き込み側)にある一定の操作が必要となります。できたら、そのような操作をさせたくなかったので、質問した次第です。