ファイル更新の監視
Posted feedbacks - Flatten
Nested Hiddenなんか根本的にわかってないかもですが・・
1 2 3 4 5 6 7 8 9 10 11 12 13 | (use file.util)
(define filename "hoge.txt")
(define (modify-checker)
(let loop ((lastmodified (file-mtime filename)))
(sys-sleep 3)
(if (= lastmodified (file-mtime filename))
(loop lastmodified)
(begin (print "modified!")
(loop (file-mtime filename))))))
(modify-checker)
|
1 2 3 4 5 6 7 8 | last_mtime = File.mtime(filename)
loop do
unless (mtime = File.mtime(filename)) == last_mtime
puts "modified!"
last_mtime = mtime
end
sleep(0.1)
end
|
POE::Wheel::FollowTail
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | #!/usr/local/bin/perl
use strict;
use warnings;
use POE;
use POE::Wheel::FollowTail;
my $target_filename = shift;
if ( !defined $target_filename or $target_filename eq '' ) {
print "$0 <filename>\n";
exit 1;
}
POE::Session->create(
inline_states => {
_start => \&setup,
handler_input => \&handler_input,
},
args => [ $target_filename ],
);
POE::Kernel->run;
exit;
sub setup
{
my ( $heap, $target_filename ) = @_[HEAP, ARG0];
$heap->{tail_wheel} = POE::Wheel::FollowTail->new(
Filename => $target_filename,
InputEvent => 'handler_input',
);
return;
}
sub handler_input
{
print "modified!\n";
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | using System;
using System.IO;
class Program
{
static void Main()
{
string filename = @"c:\test.txt";
FileSystemWatcher fsw = new FileSystemWatcher(
Path.GetDirectoryName(filename),
Path.GetFileName(filename));
fsw.Changed += delegate(object sender, FileSystemEventArgs e)
{
Console.WriteLine("modified!");
};
while (true)
fsw.WaitForChanged(WatcherChangeTypes.All);
}
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | require 'event' # http://yagi.xrea.jp/2006/08/event.rb
filename = File.expand_path("touched.txt")
last_mtime = File.stat(filename).mtime
loop {
Win32::Event::FindChangeNotification(File.dirname(filename))
file_mtime = File.stat(filename).mtime
if last_mtime != file_mtime
puts "modified!"
last_mtime = file_mtime
else
sleep 0.1
end
}
|
$ perl watch.pl /path/to/file 3
なら3秒おきに監視みたいな感じ。
モジュール使うと反則かな?w
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | #!/usr/bin/perl
use strict;
use warnings;
use Carp::Clan qw(croak);
use File::Monitor;
my $filename = shift @ARGV;
my $duration = int(shift @ARGV || 5);
croak qq|No such file. ($filename)| unless (-e $filename);
croak qq|Invalid duration| unless ($duration >= 1);
my $monitor = File::Monitor->new;
$monitor->watch(
$filename,
sub {
my ($name, $event, $change) = @_;
if ($change) {
print "modified\n";
}
}
);
while (1) {
$monitor->scan;
sleep $duration;
}
|
モジュールの豊富さもPerlのパワーの一つだと思うのでいいんじゃないでしょうか。
ファイルの存在チェックとタイムスタンプのチェックのみを1秒周期で行っています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | import java.io.File;
public class Sample {
static final String filename = "./check";
static final long INTERVAL = 1000; // 1 sec
static final String MESSAGE = "modified!";
public static void main(String[] args) throws InterruptedException {
File checkFile = new File(filename);
long lastModified = checkFile.lastModified();
while (true) {
Thread.sleep(INTERVAL);
long lm2 = checkFile.lastModified();
if (lastModified != lm2) {
System.out.println(MESSAGE);
lastModified = lm2;
}
}
}
}
|
Cc, Ciはそれぞれ
const Cc = Components.classes;
const Ci = Components.interfaces;
されているとして、
var fw = new FileWatch("/home/zigorou/hoge.txt", 5);
fw.watch();
で5秒おきにErrorConsoleに対して更新されてればmodified表示。
fw.unwatch()で監視止める。
でももっと奇麗に書き方ありそうな気がする。Observerがそもそもあったりして(ぇ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | var FileWatch = function(filename, duration) {
this.file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
this.file.initWithPath(filename);
this.duration = duration;
};
FileWatch.prototype = {
iid: null,
lastTime: null,
watch: function() {
this.lastTime = (new Date()).getTime();
var self = this;
this.iid = setInterval(function() { self.watchFile(); }, this.duration * 1000);
},
watchFile: function() {
if (this.file.lastModifiedTime - this.lastTime > 0) {
this.log("modified");
}
this.lastTime = (new Date()).getTime();
},
log: function(message) {
Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService).logStringMessage(message);
},
unwatch: function() {
clearInterval(this.iid);
}
};
|
Squeak Smalltalk で。
1 2 3 4 5 6 7 8 9 10 11 12 | | directory filename lastModTime |
directory := FileDirectory default.
filename := 'test.txt'.
lastModTime := (directory entryAt: filename) modificationTime.
[ [ | modificationTime |
modificationTime := (directory entryAt: filename) modificationTime.
modificationTime = lastModTime ifFalse: [
Transcript cr; show: 'modified!'.
lastModTime := modificationTime].
(Delay forSeconds: 3) wait
] repeat
] forkAt: Processor userBackgroundPriority
|
POE持ち出してきた自分はもっと反則なので大丈夫だと思います:)
mtime を見ないで済むよう書き換えました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | require 'rubygems'
require 'win32/ipc' # http://rubyforge.org/projects/win32utils
require 'win32/changenotify' # http://rubyforge.org/projects/win32utils
include Win32
exit if ARGV == []
filename = File.expand_path(ARGV[0])
flags = ChangeNotify::FILE_NAME | ChangeNotify::LAST_WRITE | ChangeNotify::SIZE
cn = ChangeNotify.new(File.dirname(filename), false, flags)
loop {
cn.wait(){|sa|
sa.each {|st|
puts "modified!" if st.file_name == File.basename(filename)
}
}
}
|
同じ方針ですが、modifyされているときのアクションは純粋に副作用だけなので(printするだけ)、 (if 条件 (loop) (begin (action) (loop))) よりは (unless 条件 (action)) (loop) のように副作用だけくくり出してしてしまうのが好みですね (分岐が増えた場合でもloopは一箇所にまとめられるし)。たとえば:
1 2 3 4 5 6 7 | (define (modify-checker)
(let loop ((previous #f)
(modified (file-mtime filename)))
(when (and previous (not (= previous modified)))
(print "modified"))
(sys-sleep 3)
(loop modified (file-mtime filename))))
|
EmacsLisp です :-) 毎秒、更新時刻を比較します。 (setq filename "hoge") などとして、M-x watch-modification で起動してください。 変数 filename がセットされてないなら、ファイル名を聞いてくるので指定してください。 キャンセルするには、M-x watch-modification-cancel です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | (defvar watch-modification-repeat-sec 1.0)
(defvar watch-modification-timer nil)
(defvar watch-modification-stack nil)
(defvar watch-modification-buffer "*watch*")
(defun watch-modification ()
(interactive)
(let ((file (or (and (boundp 'filename) filename)
(read-file-name "File: "))))
(unless (string= file "")
(watch-modification-cancel)
(setq watch-modification-timer
(run-with-timer 1 watch-modification-repeat-sec
'watch-modification-function file)))))
(defun watch-modification-cancel ()
(interactive)
(when watch-modification-timer
(cancel-timer watch-modification-timer))
(setq watch-modification-timer nil
watch-modification-stack nil))
(defun watch-modification-function (file)
(let ((modified-time (nth 5 (file-attributes file))))
(if (null watch-modification-stack)
(push modified-time watch-modification-stack)
(unless (equal modified-time (car watch-modification-stack))
(push modified-time watch-modification-stack)
(save-selected-window
(pop-to-buffer
(set-buffer (get-buffer-create watch-modification-buffer)))
(insert "modified!\n"))))))
|
自分も良くわかってませんが、とりあえず投稿しときます。:p
1 2 3 4 5 6 7 8 9 10 11 12 | (use file.util)
(define filename "hoge.txt")
(define (watch-modification file since nsec)
(let loop ((last-mtime since))
(sys-nanosleep nsec)
(let ((current (max (file-mtime file) last-mtime)))
(unless (= current last-mtime) (print "modified!"))
(loop current))))
(watch-modification filename (file-mtime filename) 500000000) ;0.5s
|
実は役に立たない基本形(笑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | #include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <sys/stat.h>
#include <sys/errno.h>
int moniter(const char *filename, const useconds_t interval)
{
struct stat s;
time_t last_modified = 0;
int result = 0;
printf("monitering file : %s\n", filename);
result = stat(filename, &s);
if( result == 0 )
{
last_modified = s.st_mtime;
do
{
printf("."); fflush(stdout);
stat(filename, &s);
if( last_modified < s.st_mtime )
{
printf(" modified!\n");
last_modified = s.st_mtime;
}
usleep( interval );
}while(1);
}
else
{
printf("error:%d\n", errno);
}
return 0;
}
int main(int argc, char *argv[])
{
if( argc < 2 )
{
return 1;
}
if( *argv[1] == '\0' )
{
return 2;
}
// 無限ループ 監視間隔1.5秒
moniter(argv[1], 1500);
return 0;
}
|
つづいて現実的かなと思うもの。 シグナルよりもソケットの方がいいかも。 detachして放置してもよい?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | #include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/errno.h>
#include <sys/signal.h>
static int continued = 0;
static pthread_t threads[20];
static void signal_handler(int signum)
{
continued = 0;
}
void *moniter(void *arg)
{
struct stat s;
const char *filename = arg;
time_t last_modified = 0;
int result = 0;
if( filename == NULL )
{
return NULL;
}
printf("monitering file : %s\n", filename);
result = stat(filename, &s);
if( result == 0 )
{
last_modified = s.st_mtime;
while( continued != 0 )
{
printf("."); fflush(stdout);
stat(filename, &s);
if( last_modified < s.st_mtime )
{
printf(" modified! %s\n", filename);
last_modified = s.st_mtime;
}
usleep( 8000 );
}
}
else
{
printf("error:%d\n", errno);
}
printf("monitering end[%s]\n", filename);
fflush(stdout);
return NULL;
}
size_t setup(char *filename[], size_t nFiles)
{
struct sigaction act;
int signum[] = {SIGINT};
size_t n;
int result = 0;
// シグナルの設定
for(size_t num=0; num<sizeof(signum)/sizeof(*signum); num++)
{
if( sigaction(signum[n], NULL, &act) == 0 )
{
act.sa_handler = (void (*)(int))signal_handler;
act.sa_flags &= ~SA_SIGINFO ;
result = sigaction(signum[n], &act, NULL);
}
}
// スレッドの設定
continued = 1;
for(n=0; n<nFiles; n++)
{
if( n >= 20 ) break;
result = pthread_create( &threads[n], NULL, moniter, (void *)filename[n]);
}
return n;
}
int main(int argc, char *argv[])
{
size_t nThreads = 0;
if( argc < 2 )
{
return 1;
}
if( *argv[1] == '\0' )
{
return 2;
}
nThreads = setup(argv+1, argc-1);
for(int n = 0; n< nThreads; n++ )
{
pthread_join( threads[n], NULL ); // 終了待ち合わせ
}
printf("all threads end\n");
return 0;
}
|
CLI版。
PHPでローカルファイルを監視することなんて、まず無いと思いますが一応。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #!/usr/bin/php
<?php
$filename = $argv[1];
$second = 1;
if ( file_exists($filename) ) {
$fp = fopen($filename,"r");
$fbin1 = fread($fp,filesize($filename));
fclose($fp);
}else {
exit("file not found <{$filename}>\n");
}
while (true) {
$fp = fopen($filename,"r");
$fbin2 = fread($fp,filesize($filename));
if ( $fbin1 != $fbin2 ) {
echo "modified!\n";
$fbin1 = $fbin2;
}
fclose($fp);
sleep($second);
}
?>
|
(modify-checher ファイル名) で使えます。
1 2 3 4 5 6 7 8 9 10 11 12 | (defun modify-checher (filename)
(let ((last-update nil))
(labels ((checher (stream)
(let ((present (file-write-date stream)))
(unless (equal last-update present)
(print "modified!")
(setf last-update present)))))
(with-open-file (stream filename :direction :input)
(setf last-update (file-write-date stream))
(loop do
(sleep 5)
(checher stream))))))
|
失敬。冒頭に
(defvar filename "foo.txt")
をくわえてください。^^;
最後に、
(defun file-checher2 ()
(file-checher filename))
もくわえてください。(file-checher2)でお題への回答になります。
最近のLinux用。
ファイル更新の定義が謎なのでいろいろ監視します。いろいろには、内容の変更、属性の変更、移動、削除が含まれます。ファイルを移動したりファイル名をリネームしても対象ファイルの監視を続けます。対象ファイルが削除されると監視をやめます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | /* $ gcc fnotify.c -o fnotify -Wall */
#include <sys/inotify.h>
#include <unistd.h>
#include <limits.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#define INOE_HDR_SZ offsetof(struct inotify_event, name)
static int ino_error(int ino_dev, const char *message)
{
close(ino_dev);
perror(message);
return EXIT_FAILURE;
}
int observe(const char *filename)
{
int ino_dev, ino_fd, len;
struct inotify_event *event;
char buffer[INOE_HDR_SZ + PATH_MAX];
ino_dev = inotify_init();
if (ino_dev == -1) {
perror("inotify_init");
return EXIT_FAILURE;
}
ino_fd = inotify_add_watch(ino_dev, filename,
IN_ATTRIB | IN_MODIFY | IN_MOVE_SELF | IN_DELETE_SELF);
if (ino_fd == -1) {
return ino_error(ino_dev, filename);
}
event = (struct inotify_event *)buffer;
while (1) {
len = read(ino_dev, event, sizeof(buffer));
if (len == -1 || len == 0) {
return ino_error(ino_dev, "read");
}
if (event->mask & IN_ATTRIB) {
puts("modified! (ATTRIB)");
} else if (event->mask & IN_MODIFY) {
puts("modified! (MODIFY)");
} else if (event->mask & IN_MOVE_SELF) {
puts("modified! (MOVE_SELF)");
} else if (event->mask & IN_DELETE_SELF) {
puts("modified! (DELETE_SELF)");
break;
}
}
close(ino_dev);
return EXIT_SUCCESS;
}
int main(int argc, const char **argv)
{
if (argc != 2) {
fprintf(stderr, "Usage: %s filename\n", argv[0]);
return EXIT_FAILURE;
}
return observe(argv[1]);
}
|
おお、キレイ! 勉強になります。ありがとうございます。 あと自分のでは、8行目と11行目の間に更新されると"modified!"の出力が一回少なくなってしまいますね。
短い間隔で続けざまに変更すると、modified!が一度しか表示されないことがあるので、題意を満たしてないかも。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import os, time
filename = "a.txt"
def get_mtime():
return os.stat(filename).st_mtime
mtime = get_mtime()
while 1:
time.sleep(1)
new_mtime = get_mtime()
if mtime != new_mtime:
mtime = new_mtime
print "modified!"
|
1 2 3 4 5 6 7 8 9 10 11 12 | #! /bin/bash
filename=~/tmp/check
read -n 0 < $filename
while sleep 3; do
if [ -N $filename ]; then
echo 'modified!'
sleep 1
read -n 0 < $filename
fi
done
|
posix対応。処理系はsbcl。
1 2 3 4 5 6 7 8 9 10 11 12 | (defun modify-checker (filename)
(labels ((mtime () (sb-posix:stat-mtime (sb-posix:stat filename))))
(let ((last-mtime (mtime)) current-mtime)
(loop do
(sleep 3)
(setf current-mtime (mtime))
(when (/= current-mtime last-mtime)
(format t "modified!~%")
(setf last-mtime current-mtime))))))
|
再帰。
1 2 3 4 5 6 7 8 | (defun modify-checker (filename)
(labels ((mtime () (sb-posix:stat-mtime (sb-posix:stat filename)))
(check (old-t new-t)
(when (/= old-t new-t)
(format t "modified!~%"))
(sleep 3)
(check new-t (mtime))))
(check (mtime) (mtime))))
|
カバレッジ稼ぎ。ロジックはPython版とほとんど同じ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | #include <iostream>
#include <stdexcept>
#include <windows.h>
FILETIME mtime(const char* path)
{
WIN32_FIND_DATA wfd;
HANDLE h = ::FindFirstFile(path, &wfd);
if (h == INVALID_HANDLE_VALUE)
{
throw std::runtime_error("file not found");
}
::FindClose(h);
return wfd.ftLastWriteTime;
}
int main()
{
try
{
const char filename[] = "a.txt";
FILETIME old_mtime = mtime(filename);
while (true)
{
::Sleep(100);
const FILETIME new_mtime = mtime(filename);
if (::CompareFileTime(&old_mtime, &new_mtime) != 0)
{
std::cout << "modified!" << std::endl;
}
old_mtime = new_mtime;
}
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
}
|
( ^Ï^)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | function modified(f) {
setInterval(function () {
var s = arguments.callee;
var r = new XMLHttpRequest;
r.open("GET", f, true);
r.onload = function(){
if (s.b && s.b != r.responseText)
alert("modified!");
s.b = r.responseText;
};
r.send(null);
}, 1000);
}
modified(filename);
|
JAVAと一緒。
1 2 3 4 5 6 7 8 9 10 11 12 | import java.io._
def watchFile(name:String) = {
val f = new File(name)
var last = f.lastModified
while(true){
Thread.sleep(1000)
if(f.lastModified != last) {
println("modified!")
last = f.lastModified
}
}
}
|
Pure Rなので多分OS非依存だと思います。
1 2 3 4 5 6 7 8 9 10 | watch.file <- function(file){
mtime <- file.info(file)$mtime
repeat{
if(mtime != (file.info(file)$mtime)){
mtime <- file.info(file)$mtime
print("modified!")
}
Sys.sleep(1)
}
}
|
(T,T)が、唇噛んで泣いているように見えるんです。
1 2 3 4 5 6 | watch(Filename,MTime):-sleep(0.1),time_file(Filename,MTime0),modified(MTime0,MTime),watch(Filename,MTime0).
modified(_,0).
modified(T,T).
modified(_,_):-writeln(modified).
:-watch('./watch.pl',0).
|
Haskell練習中。 GHCのSystem.Posixモジュール使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 | import Maybe
import Directory
import System.Posix
watchFile filename = watchIt Nothing
where watchIt Nothing = do mtime <- getModificationTime filename
watchIt (Just mtime)
watchIt (Just prev) = do mtime <- getModificationTime filename
if (prev < mtime)
then putStrLn "modified!"
else return ()
sleep 3
watchIt (Just mtime)
|





にしお
#3371()
Rating0/0=0.00
もしOSに依存する場合はそのOS名のタグを、 依存しない場合は「OS非依存」というタグをつけてください。 わからなければつけなくても構いません。
[ reply ]