HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2014
1125
ニボッシーrepeatでdirlistによる負担15解決


ニボッシー

リンク

2014/11/25(Tue) 17:27:44|NO.66174

いつもお世話になっております。

特定のフォルダをdirlistで監視し、
ファイル数が変動あると次のステップに進む命令を作っているのですが
dirlistの対象フォルダにたくさんファイルがある場合どうやってもCPU使用率が高くなってしまいます。



folder="C:\\" mes folder+"をチェック中..." *start chdir folder notesel list1 dirlist list1,"*.*",0 : list1size=notemax notesel list2 repeat wait 10 dirlist list2,"*.*",0 : list2size=notemax if list1size ! list2size : dialog "ファイル数に変動がありました。" : break loop goto *start

実際には別のフォルダが対象ですが
もっと動作の軽いスマートなファイルのチェックの仕方はないでしょうか?



この記事に返信する


SOU1

リンク

2014/11/25(Tue) 17:33:02|NO.66175

一定時間ごとに監視するのはそもそも負荷が高いですよね。
Win32APIのReadDirectoryChangesが最適解かと思います。

http://d.hatena.ne.jp/s-kita/20100707/1278512099
http://nienie.com/~masapico/api_ReadDirectoryChangesW.html

上記URLはHSPの内容ではありませんが
読み替えて利用すればHSPでも大丈夫かと思います。
kernel32.asに記載されていますのでincludeしてお試し下さい。



skyblue

リンク

2014/11/25(Tue) 17:38:48|NO.66176

wait 10ではなく精度の高いawaitを使うおよびawaitで1000以上waitで100以上を使う。
何のために使うかは知りませんが毎秒監視していれば十分な気がします。
頻度を下げればその分下がります。
waitは1で1/100秒なのでそんなに早く保存されるはずがないし
2〜3秒に一回どころか数十秒に1回くらいで十分な気がします。
ちなみにdirlist自体がかなり重い処理です。



ニボッシー

リンク

2014/11/25(Tue) 19:42:03|NO.66182

>SOU1さん
HSPでAPIを実装する時どういう風に記入したらいいかよく分からず
自分でAPIの登録(?)をやったことがありません。
こんな感じに使うのでしょうか?



#uselib "KERNEL32.DLL" #func global ReadDirectoryChangesW "ReadDirectoryChangesW" wptr,wptr,wptr,wptr,wptr,wptr,wptr,wptr folder="C:\\" repeat wait 10 ReadDirectoryChangesW folder,folcheck,buf,0,FILE_NOTIFY_CHANGE_FILE_NAME if folcheck!0 : break loop dialog "ファイル数に変動がありました"


>skyblueさん
小容量のファイルがたくさん入る場所なのでwaitを短めにやっています。
標準命令ではdirlistでしか増減したファイルを判別する方法が思いつかずお手上げ状態でした。



cats

リンク

2014/11/25(Tue) 20:59:30|NO.66183

ReadDirectoryChangesWはまずCreateFileでディレクトリのハンドルを取得する必要があります。
最後の2つのパラメータはNULLで構いません。



nepisat

リンク

2014/11/25(Tue) 21:07:56|NO.66184

引数には
http://chokuto.ifdef.jp/urawaza/datatype.html
ここを参考に適切なデータ型を

SOU1さんがおっしゃっていたサイト(http://nienie.com/~masapico/api_ReadDirectoryChangesW.html)に乗っている

BOOL bResult; HANDLE hDir; BYTE Buf[10000]; DWORD RetBytes; FILE_NOTIFY_INFORMATION *pInfo; DWORD i = 0; WCHAR FileName[1000]; hDir = CreateFile( L"c:\\doc\\", FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); bResult = ReadDirectoryChangesW( hDir, Buf, 10000, TRUE, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME, &RetBytes, NULL, NULL);
この部分をHSP用に書き直します。



nepisat

リンク

2014/11/25(Tue) 21:53:03|NO.66189

Sample作ってたが、HSPが強制終了(たまにいきなりHSPは動作しなくなりましたでる)
やる気なくしたのでやったことを書く参考程度に

http://w10.oroti.net/~timetag/pukiwiki/index.php?GetTimetagLyrics%2Fgblconst-sysval.hsp
ここを参考に宣言されている命令をdefine
createfileはhttp://hsp.tv/play/pforum.php?mode=pastwch&num=54700
ここの一番下の部分の引数を変えるだけ
------------------ここまでできた ↓からは間違えているかも---------
ReadDirectoryChangesもcreatefileと同じ感じで(第一パラにはCreateFileのハンドルを
最後にReadDirectoryChangesを利用してスクリプトを書く



skyblue

リンク

2014/11/26(Wed) 07:27:19|NO.66190

>小容量のファイルがたくさん入る場所なのでwaitを短めにやっています。
容量ではなく更新頻度で間隔をとって下さい。



ニボッシー

リンク

2014/11/26(Wed) 22:39:37|NO.66201

>catsさん
APIを扱ったことがないため今の所
CreateFileでディレクトリのハンドルを取得の意味が理解できませんが覚えておきます。
ありがとうございました。

>nepisatさん
参考サイトありがとうございます。
サイトを見ながら調べたらここまではわかったのですが
HANDLE hDirectory, // オブジェクトハンドル
LPVOID lpBuffer, // あらゆる型のデータへのポインタ
DWORD nBufferLength, // 32ビット符号なし整数(unsigned long型 )
BOOL bWatchSubtree, // TRUE(1と定義)またはFALSE(0と定義)のブール値。通常はFALSEであるかFALSE以外であるかで識別する。
DWORD dwNotifyFilter, // 32ビット符号なし整数(unsigned long型 )
LPDWORD lpBytesReturned, // DWORD型へのポインタ

この2つがどういう型なのか分かりませんでした。
LPOVERLAPPED lpOverlapped,
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine

まだ1割ほどしか理解出来ていませんが参考サイトをじっくりみながら
トライアンドエラーでやってみます。ありがとうございました。

>skyblueさん
説明不足で申し訳ありません。
小さい容量のファイルの書き換えが頻繁にあるフォルダのため
ファイル作成、削除されたら最速で動作させたいためこのようなwaitになっています。



mamo

リンク

2014/11/27(Thu) 01:11:48|NO.66203

だいぶ前にフォルダ監視用にとメモ取ってたやつを。
・フォルダサイズの監視

pathname = dir_exe onexit *exit s = 0 newcom oFS, "Scripting.FileSystemObject" repeat if oFS("FolderExists", pathname) { oFolder = oFS("GetFolder", pathname) if xxx ! oFolder("Size") : s ++ xxx = oFolder("Size") title "" + s + " / " + oFolder("Size") ;/1024 + "KB" } wait 10 loop stop *exit delcom oFS end

元となったものを探したけれど見つけられなかったです。
的外れだったらゴメンね。



Him

リンク

2014/11/27(Thu) 01:37:26|NO.66204

単純にファイル数を数えるとか

#uselib "kernel32" #func global FindFirstFile "FindFirstFileA" sptr,sptr #func global FindNextFile "FindNextFileA" sptr,sptr #func global FindClose "FindClose" sptr sdim lpFindFileData, $140 Dir = dir_exe chdir Dir gosub *Search mes n bak = n repeat gosub *Search if bak != n : dialog "ファイル数に変動がありました。", 0, str (n) : break wait 10 loop end *Search lpFileName = "*" FindFirstFile lpFileName, varptr (lpFindFileData) hFile = stat n = 0 repeat FindNextFile hFile, varptr (lpFindFileData) if stat = 0 { FindClose hFile break } memcpy flg, lpFindFileData, 4, 0, 0 flg And $10 if flg = 0 : n++ await loop return



skyblue

リンク

2014/11/27(Thu) 16:34:57|NO.66207

>小容量のファイルがたくさん入る場所なのでwaitを短めにやっています。
そんなに頻繁に作成と削除とか起こりますか?
起こるのでしたらプログラムの作りが悪いだけです。
そんなに頻繁にファイルの作成と削除をするのはHDDやSDDに良くないプログラムです。



ニボッシー

リンク

2014/11/27(Thu) 20:29:06|NO.66212

>mamoさん
その発想は思いつきませんでした!目から鱗です!
容量チェックが必要なプログラムの時ぜひ使わせて下さい。

>Himさん
自分の用途にぴったりのものでした!ありがとうございます!
こちらのソースを参考にAPIの勉強させてもらいますね。

>skyblueさん
確かにそうかもしれませんね・・・
自分のプログラムにはそういうことがないように気をつけていきたいものです。

皆さんありがとうございました!
自分でもAPIが使えるように勉強してみます。



zakki

リンク

2014/11/27(Thu) 22:01:18|NO.66215

ファイル名の長さとファイル数どの程度ですか?
dirlist(で使われてるstrbuf.cpp)の実装上、同一フォルダに数千〜数万のファイルがあると
あまり効率的じゃありません。



暇人

リンク

2014/11/27(Thu) 22:03:37|NO.66216

もう解決してるけど
ファイル数の変化だけ分かれば良いなら(ファイル名の変更も感知するが・・・)

#module #uselib "kernel32" #cfunc global _FindFirstChangeNotification "FindFirstChangeNotificationA" sptr,int,int #func global FindNextChangeNotification "FindNextChangeNotification" int #func global FindCloseChangeNotification "FindCloseChangeNotification" int #cfunc global WaitForSingleObject "WaitForSingleObject" int,int #define global FILE_NOTIFY_CHANGE_FILE_NAME $1 #define global FILE_NOTIFY_CHANGE_DIR_NAME $2 #define global FILE_NOTIFY_CHANGE_ATTRIBUTES $4 #define global FILE_NOTIFY_CHANGE_SIZE $8 #define global FILE_NOTIFY_CHANGE_LAST_WRITE $10 #define global FILE_NOTIFY_CHANGE_SECURITY $100 #define global WAIT_OBJECT_0 0 //指定したオブジェクトがシグナル状態になったことを意味します。 #define global WAIT_ABANDONED $80 //放棄されたミューテックスオブジェクトでした #define global WAIT_TIMEOUT $102 //タイムアウト時間が経過し、指定されたオブジェクトが非シグナル状態であったことを意味します。 #define global WAIT_FAILED $FFFFFFFF //変更通知ハンドルを作成 //[ 変数 = FindFirstChangeNotification(pn, ws ,filter) ] //pn = 監視するディレクトリの名前 //ws = ディレクトリやディレクトリツリーの監視用のフラグ //filter = 監視のためのフィルタ条件 #defcfunc FindFirstChangeNotification str pn,int ws ,int filter if h>0 {FindCloseChangeNotification h} h=_FindFirstChangeNotification(pn,ws,filter) return h //終了時に自動で呼ばれる #deffunc fccn onexit FindCloseChangeNotification h return #global PathName=dir_cur //パスを指定、サブフォルダは対象外(1にするとサブフォルダも含む)、ファイル名又はファイル数変更を監視 handle=FindFirstChangeNotification( PathName,0,FILE_NOTIFY_CHANGE_FILE_NAME) if handle>0 {mes PathName +" を監視します"}else{dialog "ハンドルが取得できません":end} repeat wait 0 //待機時間100msで監視(変更があれば即座に抜ける) if WaitForSingleObject(handle,100) = WAIT_OBJECT_0 {dialog "ファイル名又はファイル数に変化有り"} //次の変更を監視(これが無いと一度変更されたフラグがクリアされず次も感知してしまう) FindNextChangeNotification handle loop



ニボッシー

リンク

2014/11/27(Thu) 22:17:54|NO.66217

>zakkiさん
7000程ありました。
確かに100程度なら問題なかったですが数千行ったらかなり重くなりましたね。

>暇人さん
サブディレクトリまで感知出来るのはすごいですね!
サブディレクトリを読み込むのはdirlist使ってrepeatして読み込んでしか思いつかなかったので
今後使わせていただくかもしれません!ありがとうございました!



ONION software Copyright 1997-2021(c) All rights reserved.