サーバーサイドで動くプログラム(PHP,Java等)について質問です。
当方、VBA、C等を多少知っていますが、PHP,JAVA等はほとんど知りませんので、下記アルゴリズムに寄らなくても目的を達すれば良いです。
●目的
EXCELがCSVで生成した日報のようなものをマクロでWEBへアップロードすると、サーバーが自動でマスタデータへ統合(単純にマスタCSVデータの末尾へ追加)する。データベースの使用は現在見送っている。
●環境
コメント欄に示す。
●依頼内容
「当該フォルダにCSVファイルがアップロードされると、自動で同フォルダのCSVマスタデータ(MasterTest.csv)の末尾へそのデータを追加する(アップロードされたCSVファイルは消滅して良い)」サーバー用のプログラム群を作り、導入の方法を示して下さい。もし可能なら、上書き完了の是非を示す返り値を返す。
また、この前段階からのプログラムの作成でも結構です(その場合、やはりお気持ちのみですがプラス500ポイント程度)。
アルゴリズムや要件の確認・修正アドバイスがあればお願い致します。
以下、Pythonで作成した例です。
60秒間隔で指定したフォルダのCSVファイルをチェックし、ファイルが2つ以上存在する場合は追加されたと判断し、マスタCSV以外の中身を末尾に追加します。
# coding: utf-8 import os,glob,time def check(): #監視フォルダ dn = "/var/ftp/usrid" #マスタCSV mfn = os.path.join(dn,"master.csv") #フォルダ内のCSVファイル一覧 l = glob.glob(os.path.join(dn,"*.csv")) #ファイル数が2以上なら追加 if len(l)>=2: fp=open(mfn,"a+") for r in l: if r==mfn: continue data = open(r).read() fp.write(data) os.remove(r) fp.close() if __name__=="__main__": while 1: check() time.sleep(60)
上記内容を、適当なファイル名(例:check.py)として保存します。
そして、
$ python check.py &
などとして、プログラムをバックグラウンドで実行すれば「master.csv」にその他のCSVファイルの内容がそのまま追加されます。
※
フォルダ内にCSVファイル以外のファイルやフォルダがないことを前提に作成しています。
また、十分な動作検証はしていませんのでご自分で動作の確認をしてください。
(上記スクリプトによって何かあっても責任は持てませんのでよろしくお願いします。)
>場所はどこにおけば良いでしょうか?サーバー上のcsvが存在するフォルダですか?
場所はどこでも大丈夫です。ただし、CSVとは別のフォルダにしてください。
※先程書き忘れたのですが、保存する際は「監視フォルダ」と「マスタCSV」を環境に合わせて必ず修正してください。
また、複数のフォルダを監視したい場合はこのスクリプトを複数作成し、「監視フォルダ」と「マスタCSV」の箇所のみ書き換えてください。
>この方法が分からないので、教えて頂けませんか?サーバーのバックグラウンドで実行するのでしょうか。
SSHでログインして、ファイルを保存したフォルダで上記のコマンドを実行します。
>また、CoreServerは1時間以内のcronの実行が許可されていないようですが、上記方法はそれを回避するものでしょうか。尚、更新は1時間でも構いません。
この方法はcronを使うわけではないので、この制限には引っかからないと思います。(もし他にプログラムの実行に関する制限がある場合は確認が必要かもしれません。)
またcronを使用して1時間に1回の実行でよいのであれば、
if __name__=="__main__": while 1: check() time.sleep(60)
を、
if __name__=="__main__": check()
に書き換えて、cronに登録してください。(こちらのほうがプログラムの停止の心配が少ないです)
$ crontab -e 0 * * * * python プログラムのフルパス
ありがとうございます。
1:早速サーバー上でCronを登録してみましたが、指定した時間に以下のようなメールがCronのDaemonからメールでレポートされてきて、指定のcsvファイルは統合されていませんでした。何か修正する必要がありますか?
/virtual/・・・/files/cgi/check.py: line 3: syntax error near unexpected token `('
/virtual/・・・/files/cgi/check.py: line 3: `def check():
'
尚、レポートの全文はコメント欄に示しました。
2:
if __name__=="__main__":
while 1:
check()
time.sleep(60)
のプログラムの実行回数を60回(あるいはそれ以下)として、
1時間ごとにcronを利用して再実行、ということで
「毎分実行、万が一停止してしまっても少なくとも1時間に1回」
実行する、というプログラムにすることはできませんでしょうか?
また、できる場合、プログラムを示して頂けませんでしょうか。
よろしくお願い致します。
シェルスクリプトでも可能な気がします。手順は以下の通りです。
1. サーバー上にcheck.shという名前で以下の内容のファイルを作ります。
/home/yourid/の部分はサーバのホームディレクトリなどに書き換えてください。
#!/bin/bash
WORKDIR=/home/yourid/data # 監視ディレクトリ
BACKDIR=/home/yourid/back # 処理済ファイル保管場所
LOGFILE=/home/yourid/log.txt # 処理結果ログファイル名
INPUT=*.csv
OUTPUT=MasterTest.csv
cd $WORKDIR
find $INPUT \! -name $OUTPUT -exec cat {} >> $OUTPUT \; 2>/dev/null
find $INPUT \! -name $OUTPUT -exec echo `date` {} "を処理しました" >> $LOGFILE \; 2>/dev/null
find $INPUT \! -name $OUTPUT -exec mv {} $BACKDIR \; 2>/dev/null
## find $INPUT \! -name $OUTPUT -exec rm {} \; 2>/dev/null
2. SSHでログインして実行権限をつける
$ chmod +x check.sh
3. dataディレクトリとbackディレクトリを作る
$ mkdir data
$ mkdir back
4. 手動で実験してOKならCRONに登録する
$ ./check.sh
log.txtに処理結果が記録されます。
一応末尾に追加するファイルをbackディレクトリに移動して保存していますが、不要でしたらcheck.shの末尾部分を
## find $INPUT \! -name $OUTPUT -exec mv {} $BACKDIR \; 2>/dev/null
find $INPUT \! -name $OUTPUT -exec rm {} \; 2>/dev/null
このように変更してください。
ありがとうございます。
大変恐縮なのですが、できれば、SSHでのログインは避けたいと思います。
上記プログラムのうち、SSHでのログイン&実行は、確認のためだけでしょうか?(CRONに登録するだけでも大丈夫ですか?)
その理由は
1:SSHでログインの方法が良く分かっていない
2:調べたところ、使用しようとしているXreaサーバーは、SSHでのログインについて、慣れた人でも設定が面倒
3:これから複数のXreaサーバーで同様のことを試みる予定がある
このため、SSHログインの必要が無い環境での実行がもっとも望ましいと考えるようになりました。
お手数ですが、SSHログインが必要な場合は、Phthon+Cronの実行等でも結構ですし、そうでなくとも結構です。他にもし方法があれば教えて下さいませんでしょうか。上記方法は早速今から試してみます。
なるほどSSHは避けたいのですね。
>上記プログラムのうち、SSHでのログイン&実行は、確認のためだけでしょうか?
SSH以外で、ディレクトリを作ることが可能であれば特にSSHである必要はありません。
シェルスクリプトは check.shをcronに設定するだけでも動作すると思います。
ありがとうございます。無事設定できましたが、CRONで設定した時間になるとエラーレポートがメールで送られてきました。
/virtual/・・・/files/cgi/check.sh: line 7: cd: /virtual/・・・/files/csv/tts1
: No such file or directory
/virtual/・・・/files/cgi/check.sh: line 8: /dev/null
: Permission denied
/virtual/・・・/files/cgi/check.sh: line 9: /dev/null
: Permission denied
/virtual/・・・m/files/cgi/check.sh: line 10: /dev/null
: Permission denied
・・・は省略しています。「/virtual/・・・/files/csv/tts1」フォルダはちゃんとありますし、その中にmaster.csvファイル、up.csvファイル、backとlogフォルダもちゃんと作ったのですが・・・原因は推測できますでしょうか?
以下の二つを試してみてください
・check.shの 2>/dev/null という文字列を全部削除する。
・「/virtual/・・・/files/csv/tts1」フォルダのパーミッションをグループ・その他とも実行・読み込み・書き込みを出来るようにする
パーミッションの変更については、CORESERVERのファイルマネージャ(?)のヘルプを参照してみてください。
もし、FFFTPを使用しているのであれば
こちらを参考にしてみてください。
ありがとうございます。
FFFTPでしたので、パーミッションの変更が完了できました。
・check.shの 2>/dev/null という文字列を全部削除する。
>実行しました。
・「/virtual/・・・/files/csv/tts1」フォルダのパーミッションをグループ・その他とも実行・読み込み・書き込みを出来るようにする
>「/virtual/・・・/files/csv/tts1/master.csv」などのパーミッションは変更する必要は無いのでしょうか。
これで設定が完了したので、30分後のCRONで動作が確認できそうです。
追記
結果:以下エラーでした。
/virtual/・・・/files/cgi/check.sh: line 7: cd: /virtual/・・・/files/csv/tts1
: No such file or directory
find: missing argument to `-exec'
find: missing argument to `-exec'
find: missing argument to `-exec'
これまで回答されたものとは全く異なるアプローチですが、もしウェブサーバを利用できる環境であれば、
WEB を使用した更新というのもありかと思います。
下記はファイルをウェブ画面よりアップロードし、その際にマスタファイルに追記しています。
アップロードしたファイルは指定フォルダに蓄積されていき、当日アップロードされたものが画面上に
リストされるようにしています。
Webサーバの CGIフォルダ(cgi-bin 等)に下記をupload.cgi 等で保存し、ブラウザで
http://サーバ名/cgi-bin/upload.cgi
のようにしてアクセスします。
コードは下記をベースに、カスタマイズしています。
http://nais.to/~yto/tools/ssupload/
詳細の設定方法は、お使いのサーバでご確認ください。
#!/usr/bin/env perl use strict; use CGI; use CGI::Carp qw(fatalsToBrowser); use POSIX qw(strftime); use File::Spec; my $q = new CGI; print $q->header(-charset => 'Shift-JIS'), $q->start_html(); #---------------------------------------------------------------- # ★★★実際のファイルパスに変更 #---------------------------------------------------------------- my $outputdir = "/home/database/log"; # ファイルを置く先 (ディレクトリ) my $masterCsv = "/home/database/masterTest.csv"; # アップロードしたファイルを追加先ファイル my $fh = $q->param('uploaded_file'); my ($mvolume,$mdirectories,$mfile) = File::Spec->splitpath( $masterCsv ); if ($fh ne "") { my $timestamp = strftime "%y%m%d%H%M%S", localtime; my ($avolume,$adirectories,$afile) = File::Spec->splitpath( $fh ); my $outputfn = "$outputdir/${timestamp}_$afile"; open( IF, "> $outputfn") or die; open( AF, " >> $masterCsv" ) or die; flock(F, 2); if (defined $fh) { while (<$fh>) { print F $_; print AF $_; } } close F; close AF; print qq{<a href="$outputfn">$afile</a> を $mfile に追記しました。}; } $q->delete_all(); print qq(<p><a href="@{[$q->self_url]}">RELOAD</a></p>); print $q->start_multipart_form(-name => 'myform'), "FILE ", $q->filefield(-name => 'uploaded_file'), $q->submit("OK"), $q->endform; my $today = strftime "%y%m%d", localtime; my @fl = reverse <$outputdir/${today}*>; my @fll = map { my ($avolume,$adirectories,$afile) = File::Spec->splitpath( $_ ); $afile } @fl; print "<ul>", (map {qq(<li><a href="$_" target="_blank">$_</a> )} @fll), "</ul>"; print $q->end_html(), "\n";
実行画面
ただ、これはだれでもアクセスできてしまうので、インタネット上で運用する場合は、Basic 認証等で
アクセスを制限したほうがよいでしょう。
http://allabout.co.jp/internet/hpcreate/closeup/CU20020910A/
いつも、ありがとうございます。
先ほど試してみたところ、無事アップロード&統合ができました。
さて、ファイルのアップロード&統合はVBAアプリケーション(ユーザーフォーム)からボタン一つで自動化したいのですが、その方法がありましたら教えて頂くことはできませんでしょうか?
上記で教えて頂いたWEBアップロードによる方法以外、まだ実現できておらず、困っています。
もしよろしければ、そちらのほうもご教授頂ければ幸いです。
早速ありがとうございます。
>上記内容を、
ここまで分かりました。
>適当なファイル名(例:check.py)として保存します。
場所はどこにおけば良いでしょうか?サーバー上のcsvが存在するフォルダですか?
>などとして、プログラムをバックグラウンドで実行すれば
この方法が分からないので、教えて頂けませんか?サーバーのバックグラウンドで実行するのでしょうか。
また、CoreServerは1時間以内のcronの実行が許可されていないようですが、上記方法はそれを回避するものでしょうか。尚、更新は1時間でも構いません。