ファイル更新の監視
Posted feedbacks - Nested
Flatten 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)
|
同じ方針ですが、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))))
|
おお、キレイ! 勉強になります。ありがとうございます。 あと自分のでは、8行目と11行目の間に更新されると"modified!"の出力が一回少なくなってしまいますね。
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
}
|
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)
}
}
}
|
$ 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のパワーの一つだと思うのでいいんじゃないでしょうか。
POE持ち出してきた自分はもっと反則なので大丈夫だと思います:)
ファイルの存在チェックとタイムスタンプのチェックのみを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
|
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]);
}
|
短い間隔で続けざまに変更すると、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)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 | function monitor(filename) monitor(filename, 1000, "modified!")
function monitor(filename, interval, message){
f = getFile(filename)
lm = f.lastModified()
while (true){
sleep(interval)
m = f.lastModified()
if (m != lm){
println(message)
lm = m;
}
}
}
|
Timer と TimerTask を使ってみました。
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 | import java.io.File;
import java.util.TimerTask;
public class FileCheck extends TimerTask {
private File targetFile;
private long lastModify;
public FileCheck(String filename){
if(filename == null)
throw new IllegalArgumentException();
targetFile = new File(filename);
lastModify = targetFile.lastModified();
}
@Override
public void run() {
long modify = targetFile.lastModified();
if(modify != lastModify)
doModifiedAction();
lastModify = modify;
}
protected void doModifiedAction() {
System.out.println("modified!");
}
}
import java.util.Timer;
public class FileChekMain {
public static void main(String[] args) {
String filename = "./bin/aaa.txt";
Timer timer = new Timer();
timer.schedule(new FileCheck(filename), 1000L,1000L);
}
}
|
$ observe-mtime -c 'echo "modified!"' filename いつも使っているスクリプトでいけそうなのでまんま投稿します。 ・複数ファイルを監視できます ・任意のコマンドを実行できます ・監視間隔を指定できます
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 | #!/usr/bin/env perl
use strict;
use warnings;
use Pod::Usage;
use Getopt::Long;
use File::Modified;
my $Interval = $ENV{INTERVAL} || 3; # sec
my $command;
Getopt::Long::Configure("bundling");
GetOptions(
'command|c=s' => ¥$command,
'help|h|?' => sub { pod2usage() },
) or pod2usage;
my @files = @ARGV;
pod2usage unless $command;
### @files
### $command
my $o = File::Modified->new(files=>[ @files ]);
my @changes;
while (1) {
if (@changes = $o->changed) {
### @changes
print qx{ $command };
$o->update;
}
### sleep: $Interval
sleep $Interval;
}
__END__
=head1 SYNOPSIS
observe-mtime -c command file [file...]
=cut
|
適当です。バイナリは使えないぜ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | //HSPでファイル更新確認プログラム
*config
//監視するファイル名
filename = kansi.txt
//確認する間隔(1000の1分秒 1000で1秒)
times = 20
//以下、プログラム
puel = ""
goto *gurdman
*gurdman
notesel puel
noteload filename
if puel != pool {
gosub *alert
}
pool = puel
await times
*alert
mes "modified!"
|
すいません、最後の行にreturnいれてください。修正版は
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | //HSPでファイル更新確認プログラム
*config
//監視するファイル名
filename = kansi.txt
//確認する間隔(1000の1分秒 1000で1秒)
times = 20
//以下、プログラム
puel = ""
goto *gurdman
*gurdman
notesel puel
noteload filename
if puel != pool {
gosub *alert
}
pool = puel
await times
*alert
mes "modified!"
return
|
kansi.txt は わざとですよね?
system() から test, touch, sleep, rm を呼び出しています。ほとんどシェルスクリプトです。これを敢えてawkで書くメリットはないです。 % awk -f kanshi.awk -v filename=foobar
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | BEGIN {
srand ; rand ; rand
tmpfile = sprintf("/tmp/kanshi%06d", rand*1000000)
# create tmpfile
system("touch -r " filename " " tmpfile)
while (1) {
r = system("test " filename " -nt " tmpfile) # if filename is newer than tmpfile
if (r == 0) {
# message
print "modified!"
# synchronize
system("touch -r " filename " " tmpfile)
}
if (system("sleep 1")) break # aborted
}
# remove tmpfile
system("rm -f " tmpfile)
exit
}
|
OS非依存、GHC依存(threadDelay) チェックは1秒毎
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | module Main (main) where
import Control.Monad (when)
import Control.Concurrent (threadDelay)
import Data.Maybe (maybe, listToMaybe)
import System.Directory (getModificationTime)
import System.Environment (getArgs)
import System.IO.Error (catch)
import System.Time (ClockTime, getClockTime)
main :: IO ()
main = flip watchFile Nothing . maybe "." id . listToMaybe =<< getArgs
watchFile :: FilePath -> Maybe ClockTime -> IO ()
watchFile file prev
= catch (threadDelay (1*1000000) >> check prev)
(const $ watchFile file . Just =<< getClockTime)
where
check Nothing = watchFile file . Just =<< getModificationTime file
check (Just mtime) = do { mtime' <- getModificationTime file
; when (mtime < mtime') (putStrLn "modified!")
; watchFile file (Just mtime')
}
|
SchemeというかGaucheですが。 しかも超亀レスですが。
1 2 3 4 5 6 7 8 9 10 11 12 13 | (use file.util)
(define filename "hoge.txt")
(define (make-file-modification-monitor fname sleep on-modified)
(define (mon c)
(let1 n (file-mtime fname)
(unless (= c n) (on-modified))
(sleep)
(mon n)))
(cut mon (file-mtime fname)))
((make-file-modification-monitor filename (cut sys-sleep 1) (cut print "modified!")))
|
tail -f の動作を調べて、参考にしました。
kevent, kqueue を使っているので BSD 限定だと思います。
簡単のためファイル名変更と削除には対応していません。
kevent, kqueue を使っているので BSD 限定だと思います。
簡単のためファイル名変更と削除には対応していません。
see: tail.c
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 | #include <sys/types.h>
#include <sys/stat.h>
#include <sys/event.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
int main ( int argc, char *argv[] ){
struct stat sb;
struct kevent kev;
int kq, fd;
if( argc < 2 ){
fprintf(stderr,"Usage: %s filename\n", argv[0] );
return EXIT_FAILURE;
}
if( stat( argv[1], &sb ) == -1 ){
fprintf(stderr,"%s is not acceessible\n", argv[1] );
return EXIT_FAILURE;
}
if( !S_ISREG( sb.st_mode ) ){
fprintf(stderr,"%s is not regular file\n", argv[1] );
return EXIT_FAILURE;
}
if( (fd = open( argv[1], O_RDONLY )) == -1 ){
fprintf(stderr,"open(\"%s\") failed\n", argv[1] );
return EXIT_FAILURE;
}
kq = kqueue();
EV_SET( &kev, fd, EVFILT_READ, EV_ADD | EV_ENABLE | EV_CLEAR , 0, 0, 0 );
if( kevent(kq, &kev, 1, NULL, 0, NULL) < 0 ){
fprintf(stderr,"kevent failed\n" );
return EXIT_FAILURE;
}
while(1){
kevent(kq, NULL, 0, &kev, 1, NULL);
printf("modified!\n");
}
return EXIT_SUCCESS;
}
|
プラス評価ありがとうございます。
- 初回のイベント通知は捨てる。
- close 処理を追加。
を追加してみました。
- 初回のイベント通知は捨てる。
- close 処理を追加。
を追加してみました。
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 | --- main.c.org Thu Nov 15 23:18:57 2007
+++ main.c Thu Nov 15 23:23:17 2007
@@ -4,7 +4,13 @@
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+int received_sigint;
+void sigint_handler( int sig ){
+ received_sigint = 1;
+}
int main ( int argc, char *argv[] ){
@@ -33,6 +39,11 @@
return EXIT_FAILURE;
}
+ if( signal(SIGINT, sigint_handler) == SIG_ERR ){
+ fprintf(stderr,"couldn't register SIGINT handler\n");
+ return EXIT_FAILURE;
+ }
+
kq = kqueue();
EV_SET( &kev, fd, EVFILT_READ, EV_ADD | EV_ENABLE | EV_CLEAR , 0, 0, 0 );
@@ -40,9 +51,16 @@
fprintf(stderr,"kevent failed\n" );
return EXIT_FAILURE;
}
+ kevent(kq, NULL, 0, &kev, 1, NULL);
while(1){
- kevent(kq, NULL, 0, &kev, 1, NULL);
+ if( kevent(kq, NULL, 0, &kev, 1, NULL) == -1 ){
+ if( !received_sigint ){
+ perror("error");
+ }
+ break;
+ }
printf("modified!\n");
}
+ close(fd);
return EXIT_SUCCESS;
}
|
NSRunLoopで回すのはいいのかどうか分かりません。NSTimerを使いたくてこの形に。 一応Leopardタグ付けますがfor ~ in ~のところをNSEnumeratorを使うように書き換えればXcode2.xでもコンパイルできるはず。 あと、Leopardだとそのままずばりファイルの監視をするFSEventというAPIがあります。 TimeMachineが使ってるやつ。これはCなんですが、詳細は参考ページ参照で。
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 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | #import <Foundation/Foundation.h>
#define WATCH_PATH @"target path"
#define WATCH_FILE_ATTR @"target file atrributes"
#define WATCH_FILE_MODIFIED @"target file modified"
@interface Watcher : NSObject
{
NSMutableDictionary *targetPathes;
NSFileManager *manager;
NSMutableDictionary *fileAttributes;
}
- (id)initWithTargetPathes:(NSArray *)pathes;
- (void)checkModified;
@end
@implementation Watcher
- (id)initWithTargetPathes:(NSArray *)pathes;
{
targetPathes = [NSMutableDictionary dictionary];
manager = [NSFileManager defaultManager];
fileAttributes = [NSMutableDictionary dictionary];
for (NSString *path in pathes)
{
[targetPathes setValue:path forKey:path];
NSDictionary *status = [manager fileAttributesAtPath:path traverseLink:YES];
if (status) [fileAttributes setValue:status forKey:path];
}
return self;
}
- (void)sendNotification:(NSString *)aPath withStatus:(id)aStatus
{
NSString *message = [NSString stringWithFormat:@"'%@' is modified!", aPath];
[[NSNotificationCenter defaultCenter] postNotificationName:WATCH_FILE_MODIFIED
object:message
userInfo:aStatus];
return;
}
- (void)checkModified
{
for (NSString *path in targetPathes)
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSDictionary *_prev = [fileAttributes objectForKey:path];
NSDictionary *_current = [manager fileAttributesAtPath:path traverseLink:YES];
if (_prev || _current)
{
if (!_current)
{
[fileAttributes removeObjectForKey:path];
[self sendNotification:path withStatus:nil];
}
else if (![_current isEqual:_prev])
{
[fileAttributes setObject:[_current copy] forKey:path];
[self sendNotification:path withStatus:_current];
}
}
[pool release];
}
return;
}
@end
@interface FileStatusLogger : NSObject
{
NSNotificationCenter* center;
}
- (id)initWithNotificationCenter:(NSNotificationCenter *)aCenter;
- (void)log:(NSNotification *)notice;
@end
@implementation FileStatusLogger
- (id)initWithNotificationCenter:(NSNotificationCenter *)aCenter
{
[super init];
[aCenter addObserver:self selector:@selector(log:) name:WATCH_FILE_MODIFIED object:nil];
return self;
}
- (id)init
{
return [self initWithNotificationCenter:[NSNotificationCenter defaultCenter]];
}
- (void)log:(NSNotification *)notice;
{
NSLog(@"%@", [notice object]);
return;
}
@end
void usage(name)
{
printf("Usage: %s <interval> <duration> <path1> [<path2>...]\n", name);
exit(1);
}
int main(int argc, char *argv[])
{
if (argc < 4) usage(argv[0]);
NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSMutableArray *pathes = [NSMutableArray array];
NSTimeInterval interval = strtod(argv[1], NULL);
NSTimeInterval duration = strtod(argv[2], NULL);
if (interval <= 0) usage(argv[0]);
int i;
for (i = 3; i < argc; i++)
{
[pathes addObject:[NSString stringWithCString:argv[i]]];
}
Watcher *watcher = [[Watcher alloc] initWithTargetPathes:pathes];
FileStatusLogger *logger = [FileStatusLogger new];
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:interval
target:watcher
selector:@selector(checkModified)
userInfo:nil
repeats:YES];
NSLog(@"monitoring start");
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
if (duration > 0)
{
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:duration]];
}
else
{
[[NSRunLoop currentRunLoop] run];
}
NSLog(@"monitoring end");
[pool release];
return 0;
}
|
116行目のscheduledTimerWithTimeInterval:target:selector:userInfo:repeats: のメソッドでcurrentRunLoopに登録されますので、 122行目の addTimer:...はいらないんじゃないかなぁ。
タイマーでぐるぐる回してるだけです
1 2 3 4 5 6 7 8 9 10 | filename=デスクトップ&"test.txt"
TMP=filenameのファイル更新日時
監視タイマーとはタイマー
これについて
値=1000
時満ちた時は~
もし(TMP<>ファイル更新日時(filename))ならば
"modified!"を表示
TMP=filenameのファイル更新日時
開始
|
監視は1秒毎。
1 2 3 4 5 6 7 8 9 10 11 12 13 | fun check filename =
let
val t = OS.FileSys.modTime filename
in
(OS.Process.sleep o Time.fromSeconds) 1;
if t = OS.FileSys.modTime filename then
check filename
else
(print ("modified!" ^ "\n"); check filename)
end
val _ = check "hoge.txt"
|
まだDが出ていなかったので。 標準ライブラリが使いづらくて仕方がありません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | import std.stdio, std.file, std.date, std.c.time;
void main(string[] args) {
if(args.length <= 1) return;
auto filename = args[1];
d_time lastmod = mtime(filename);
while(true) {
d_time lastmod2 = mtime(filename);
if(lastmod != lastmod2) {
writeln("modified!");
lastmod = lastmod2;
}
msleep(1000);
}
}
d_time mtime(string file) {
d_time ftc, fta, ftm;
getTimes(file, ftc, fta, ftm);
return ftm;
}
|
指定されたファイルのコピーを一時ディレクトリ(%TEMP%)に作成し、バイナリモードで元
のファイルと比較しています。タイムスタンプだけが更新された場合には検出できません。
e.g.
C:>monitor monitor.bat
指定されたファイルを監視しています。
終了するにはCtrl-Cを押してください。
02:22:22 指定されたファイルが更新されました。
Windows XPで動作を確認。fcはWindows NTにも存在するので、NTでも動作するかもしれま
せん。
# 为了妈贡献出我自己手里的全部二。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | :: monitor.bat
@echo off
setlocal
set f=%TEMP%\%~nx1
if "%1" == "" (echo %~n0 [FILE] & goto :EOF)
if not exist %1 (echo 指定されたファイルが見つかりません。 & goto :EOF)
echo 指定されたファイルを監視しています。
echo 終了するにはCtrl-Cを押してください。
echo.
copy %1 %f% >NUL
:loop
fc /b %f% %1 >NUL
if %ERRORLEVEL% equ 1 (
for /f "tokens=2 delims=. " %%t in ('echo.^|time') do echo %%t 指定されたファイルが更新されました。
copy %1 %f% >NUL
)
ping -n %1 127.0.0.1 >NUL
goto loop
endlocal
goto :EOF
|
誤りが 1つありましたので、訂正します。 20c20 < ping -n %1 127.0.0.1 >NUL --- > ping -n 1 127.0.0.1 >NUL :: 1秒間スリープ
IronPythonで書いてみました。
C#とほぼ同じになりますが、C#よりタイプ量が少ないのがうれしいですね
1 2 3 4 5 6 7 8 9 10 | import clr
import System
from System.IO import *
filename = "D:/test.php"
fw = FileSystemWatcher( Path.GetDirectoryName(filename), Path.GetFileName(filename))
def handle( w,a ):
print "modified"
fw.Changed += handle
fw.EnableRaisingEvents = True
|
MD5でチェックさせてみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | -module(checker).
-export([start/0]).
start()->
Filename="test.html",
loop(Filename,[]).
loop(F,C)->
timer:sleep(1000),
NC=erlang:md5(element(2,file:read_file(F))),
if
C =:= [] -> loop(F,NC);
C =:= NC -> loop(F,C);
C =/= NC ->
io:format("modified!~n"),
loop(F,NC)
end.
|
こちらも処理順依存です。
ocamlが左から評価するようになったら、sleepは右のstat前にいります。
ocamlが左から評価するようになったら、sleepは右のstat前にいります。
1 2 3 4 5 6 7 | (*ocaml unix.cma doukaku15.ml*)
let monitor path sec =
while true do
if (Unix.sleep sec; Unix.stat path) <> Unix.stat path
then print_endline "modified!"
done
in monitor "a.txt" 2;;
|
処理順に依存しないようにしてみました。
1 2 3 4 5 6 7 | let monitor path sec =
let rec loop stat =
Unix.sleep sec;
let next_stat = Unix.stat path in
if stat <> next_stat then print_endline "modified!";
loop next_stat
in loop (Unix.stat path)
|
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 | <?php
$filename = "testfile.txt";
$sleepTime = 1; //micro seconds
if (!($modifiedTimeOld = get_file_modified_time($filename))) {
exit("File not found.");
}
while (true) {
clearstatcache();
if (!($modifiedTimeNew = get_file_modified_time($filename))) {
exit("File not found.");
}
if ($modifiedTimeOld != $modifiedTimeNew) {
echo "modified!\n";
$modifiedTimeOld = $modifiedTimeNew;
}
usleep($sleepTime);
}
function get_file_modified_time($filename) {
if (check_file_exist($filename)) {
return filemtime($filename);
} else {
return false;
}
}
function check_file_exist($filename) {
if (!(file_exists($filename) && is_file($filename))) {
return false;
}
return true;
}
|
一秒ごとにファイルの更新日時をチェックしています。
1 2 3 4 5 6 7 8 9 10 11 | def filename = "c:/test.txt"
def file = new File(filename)
def lastModified = file.lastModified()
while(true){
if( lastModified != file.lastModified() ){
println "modified! : OS非依存 : ${file.lastModified()}"
lastModified = file.lastModified()
}
Thread.sleep(1000)
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | Option Explicit
Dim filename, fs, objFile
Dim lastDateLastModified, nowDateLastModified
filename = WScript.Arguments(0)
Set fs = CreateObject("Scripting.FileSystemObject")
If fs.FileExists(filename) = False Then
WScript.Echo(filename & " is not exists.")
WScript.Quit(1)
End If
Set objFile = fs.GetFile(filename)
lastDateLastModified = objFile.DateLastModified
Do
nowDateLastModified = objFile.DateLastModified
If lastDateLastModified <> nowDateLastModified Then
WScript.Echo "modified!"
lastDateLastModified = nowDateLastModified
End If
WScript.Sleep(10000)
Loop
|






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