• ベストアンサー

データベースを使わず、テキストファイルで・・・

SQLサーバーとかを使わずに、テキストファイルで 多人数がアクセスするプログラムを作成しました。 テキストファイルを開くときは、もちろん排他的 ロック、アンロックしていますが、心配なところです。 SQLサーバーなどを使わないで多人数(~10人程度)が 利用するプログラムはテキストファイルが壊れやすい でしょうか? 将来的には、やはりなんらかの安価なデータベースを使っ たWEBアプリに改変予定ですが、それにはどういったサーバ がおすすめでしょうか?また、作成のコツなどを教えて ください。昔、VBとSQLサーバーで社内システムを構築 した経験はありますが、離れているので技術力は 乏しいです。

質問者が選んだベストアンサー

  • ベストアンサー
  • Dpop
  • ベストアンサー率51% (279/544)
回答No.6

#3 です。 修正です。 > # データベースコネクト > db = DBI->connect('DBI:mysql:ATMARKIT:localhost', $user, $passwd); > $dbh = DBI->connect("DBI:mysql:<データベース名>:localhost", <ユーザー>, <パスワード>); は、 # データベースコネクト $dbh = DBI->connect("DBI:mysql:<データベース名>:localhost", <ユーザー>, <パスワード>); の間違えです(^_^;;) 失礼しました。

Scotty_99
質問者

お礼

お礼おそくなりました。SQLソフトを今後利用するときに参考にさせて頂きます。とても貴重な回答ありがとうございました。

その他の回答 (5)

  • Dpop
  • ベストアンサー率51% (279/544)
回答No.5

#3 です。 > ほかのDBでも同じようなコーディングメインの作業になりますよね。 RDBの場合、コーディングの方法はだいぶ違いがあります。 手元に良いサンプルが無かったのですが、DBD::CSVと言うSQLを利用してCSVファイルを読み込む例があるので、紹介します。 ----- ^ save_csv.pl ^ ----- #!/usr/bin/perl use DBI; use strict; my($dbh, $sth, $sql, $table); my(@rdata, @sexd, $rand, $i); my($id, $arg, $name, $fname, $sex); $table = "c0.csv"; @rdata = ('0' .. '9', 'A' .. 'Z', 'a' .. 'z'); @sexd = ('M', 'F'); if (-f $table) { unlink($table); } # データベースへコネクト $dbh = DBI->connect("DBI:CSV:f_dir=."); # テーブルクリエート # SQL文を作る $sql =<<"END_SQL"; CREATE TABLE $table ( id INTEGER , arg INTEGER , fname CHAR(1) , name CHAR(64) , sex CHAR(1) ) END_SQL # SQL文をパースする $sth = $dbh->prepare($sql) or die "Cannot prepare: " . $dbh->errstr(); # SQL文を実行する $sth->execute() or die "Cannot execute: " . $sth->errstr(); # データ挿入 # ランダムデータを作成する srand(time); $rand = int(rand(1000))+1000; for ($i = 0; $i <= $rand; $i++) { $id = $i+1; $arg = int(rand(70))+20; $name = $dbh->quote(&randstr(20)); $fname = $dbh->quote(substr($name, 1, 1)); $sex = $dbh->quote($sexd[int(rand(2))]); # SQL文を作る $sql =<<"END_SQL"; INSERT INTO $table VALUES ( $id , $arg , $fname , $name , $sex ) END_SQL # SQL文をパースする $sth = $dbh->prepare($sql) or die "Cannot prepare: " . $dbh->errstr(); # SQL文を実行する $sth->execute() or die "Cannot execute: " . $sth->errstr(); } # データベースを閉じる $sth->finish(); $dbh->disconnect(); exit(0); sub randstr($) { my($size) = @_; my($r, $i); $r = ""; for ($i = 0; $i <= $size; $i++) { $r .= $rdata[int(rand(scalar(@rdata)))]; } ($r); } ----- $ save_csv.pl $ ----- ----- ^ load_csv.pl ^ ----- #!/usr/bin/perl use DBI; use strict; my($dbh, $sth, $sql, $table); my($id, $arg, $name, $fname, $sex); $table = "c0.csv"; # データベースコネクト $dbh = DBI->connect("DBI:CSV:f_dir=."); # テーブル読み込み # SQL文 $sql =<< "END_SQL"; SELECT id, arg, fname, name, sex FROM $table WHERE arg >= 30 AND arg <= 39 AND sex = 'F' ORDER BY arg ASC , id ASC END_SQL # SQLパース $sth = $dbh->prepare($sql) or die "Cannot prepare: " . $dbh->errstr(); # SQL実行 $sth->execute() or die "Cannot execute: " . $sth->errstr(); # レコード読み取り $sth->bind_columns(undef, \$id, \$arg, \$fname, \$name, \$sex) or die "Cannot bind_columns: " . $sth->errstr(); while($sth->fetch) { print "id=$id arg=$arg fname=$fname name=$name sex=$sex\n"; } # データベースを閉じる $sth->finish(); $dbh->disconnect(); exit(0); ----- $ load_csv.pl $ ----- 普段から、RDBを利用している人には、こちらの方が馴染みがあるのですけどね。 > ACCESS感覚でWEBアプリが構築できればよいのですが、もしご存知であれば教えてください。 GUIでやりとりをするのは無理がありますね。例えば、AccessやExcelでデータを作り、CSVファイルとして取り出し、RDBへ格納する。と言うやり方をする事もできます。 一般に、利用者が利用する機能とは別に、管理機能があったり、データベースメンテナンス機能があったりするのが当然ですから、業務の流れやオペレータの習熟度に応じて、メンテナンス機能の一部として、CSVファイルをRDBへ反映させたり、RDBのデータをCSVファイルとして出力する機能を用意すれば良いでしょう。 この辺りは、Webアプリだから。と言うよりも、業務プログラムの管理方法論ですかね。 > 私が利用しているどめいん屋ではMySQLが利用できるそうです。ただ、むずかしそうです。本を買ってできそうか見てみようと思います。 Perl的には、 # データベースコネクト $dbh = DBI->connect("DBI:CSV:f_dir=."); を # データベースコネクト db = DBI->connect('DBI:mysql:ATMARKIT:localhost', $user, $passwd); $dbh = DBI->connect("DBI:mysql:<データベース名>:localhost", <ユーザー>, <パスワード>); と、するだけで、後はCSVでもMySQLでも変わらないのですけどね。 後は、SQLの知識と経験の問題ですかね。

  • Dpop
  • ベストアンサー率51% (279/544)
回答No.4

#3 です。 BerkeleyDBの取り扱いはそれほど難しい物ではありません。リファレンスを伴う場合には、MLDBM.pm と言うパッケージが必要になり、これは標準パッケージではありませんが(確か)、リファレンスを伴わないBerkeleyDBであれば、標準パッケージだけで扱う事ができます。 例を示しておきますので、参考にしてみて下さい。 例1) リファレンスを伴わない例 -----^ data.txt ^----- AAAAA BBBBB CCCCC DDDDD EEEEE FFFFF GGGGG HHHHH IIIII JJJJJ KKKKK LLLLL MMMMM NNNNN OOOOO PPPPP QQQQQ RRRRR SSSSS TTTTT UUUUU VVVVV WWWWW XXXXX YYYYY ZZZZZ -----$ data.txt $----- -----^ save_db.pl ^----- #!/use/local/bin/perl use Fcntl; use AnyDBM_File; my($f, $db, $c, %h); $f = "data.txt"; $db = "data.db"; $c = 1; open(IN, $f) or die "open error $f"; tie(%h, AnyDBM_File, $db, O_RDWR|O_CREAT, 0666); while(<IN>) { chop; $h{$c} = $_; $c++; } close(IN); untie(%h); exit(0); -----$ save_db.pl $----- -----^ load_db.pl ^----- #!/use/local/bin/perl use Fcntl; use AnyDBM_File; my($db, %h, $key); $db = "data.db"; tie(%h, AnyDBM_File, $db, O_RDWR, 0666); foreach $key (sort keys %h) { printf("key => %-3s data => %s\n", $key, $h{$key}); } untie(%h); exit(0); -----$ load_db.pl $----- 例2) リファレンスを伴う例 -----^ data.txt ^----- 1,AAAA,1963/04/30,AA,a1@a.ne.jp 2,AAAA,1964/01/15,BB,a2@a.ne.jp 3,BBBB,1968/10/23,AA,a3@a.ne.jp 4,AAAA,1961/01/10,BB,a4@a.ne.jp 5,BBBB,1964/01/16,BB,a5@a.ne.jp 6,BBBB,1967/05/14,AA,a6@a.ne.jp 7,AAAA,1963/04/30,AA,a7@a.ne.jp 8,AAAA,1966/03/14,BB,a8@a.ne.jp 9,BBBB,1968/10/23,AA,a9@a.ne.jp 10,BBBB,1967/09/07,BB,a10@a.ne.jp 11,AAAA,1967/09/07,AA,a11@a.ne.jp 12,AAAA,1967/11/21,AA,a12@a.ne.jp 13,BBBB,1967/09/07,AA,a13@a.ne.jp 14,BBBB,1963/04/30,AA,a14@a.ne.jp 15,AAAA,1961/01/10,AA,a15@a.ne.jp 16,AAAA,1964/01/11,BB,a16@a.ne.jp 17,AAAA,1967/09/07,BB,a17@a.ne.jp 18,BBBB,1964/01/16,BB,a18@a.ne.jp 19,BBBB,1967/09/07,AA,a19@a.ne.jp 20,BBBB,1968/05/13,AA,a20@a.ne.jp 21,AAAA,1963/4/ 1,AA,a21@a.ne.jp -----$ data.txt $----- -----^ save_db.pl ^----- #!/usr/bin/perl use strict; use AnyDBM_File; use MLDBM qw (AnyDBM_File); use Fcntl; my($f, $db, @array); $f = 'data.txt'; $db = 'data_mldbm.db'; &set($f, \@array); &write_db(\@array, $db); exit(0); sub set($$) { my($f, $array) = @_; my($no, $data1, $bday0, $data2, $email, %bday); open(IN, $f) or die("open error $f"); while(<IN>) { chomp; ($no, $data1, $bday0, $data2, $email) = split(/,/, $_); &daysplit($bday0, \%bday); my(%rec); $rec{'no'} = $no; $rec{'data1'} = $data1; $rec{'bday0'} = $bday0; $rec{'bday'} = \%bday; $rec{'data2'} = $data2; $rec{'email'} = $email; push(@{$array}, \%rec); } close(IN); } sub daysplit($$) { my($day, $sday) = @_; my(@d, $i); (@d) = split(m|/|, $day); foreach $i (0 .. 2) { $d[$i] = sprintf('%0'. ((4, 2, 2)[$i]). 'd', $d[$i]); } $sday->{'org'} = $day; $sday->{'day'} = join('/', @d); $sday->{'ymd'} = join('', @d); $sday->{'yy'} = $d[0]; $sday->{'mm'} = $d[1]; $sday->{'dd'} = $d[2]; } sub write_db($, $db) { my($array) = @_; my(%hash, $i); tie(%hash, 'MLDBM', $db, O_RDWR|O_CREAT, 0666); for ($i = 0; $i <= $#array; $i++) { $hash{$array[$i]{'email'}} = $array[$i]; } untie(%hash); } __END__; -----$ save_db.pl $----- -----^ load_db.pl ^----- #!/usr/bin/perl use strict; use AnyDBM_File; use MLDBM qw (AnyDBM_File); use Fcntl; my($db, @f, @array); $db = 'data_mldbm.db'; @f = qw(data_mldbm_0.txt data_mldbm_1.txt data_mldbm_2.txt); &load_db($db, \@array); &dump_data(\@array, $f[0]); @array = sort sortsub1 @array; &dump_data(\@array, $f[1]); @array = sort sortsub2 @array; &dump_data(\@array, $f[2]); exit(0); sub load_db($$) { my($db, $array) = @_; my(%hash, $rec); tie(%hash, 'MLDBM', $db, O_RDONLY, 0666); foreach $rec (keys %hash) { $array[$hash{$rec}{'no'}] = $hash{$rec}; } untie(%hash); } sub sortsub1 { $a->{bday}->{ymd} <=> $b->{bday}->{ymd} || $b->{data1} cmp $a->{data1} || $a->{data2} cmp $b->{data2} || $a->{email} cmp $b->{email} || $a->{no} <=> $b->{no} } sub sortsub2 { $a->{bday}->{mm} <=> $b->{bday}->{mm} || $a->{bday}->{ymd} <=> $b->{bday}->{ymd} || $a cmp $b } sub dump_data($$) { my($array, $f) = @_; my($i, $j, $k, @s); for ($i = 0; $i <= scalar(@{$array})-1; $i++) { foreach $j (sort keys %{$array[$i]}) { if (ref($array[$i]{$j}) eq 'HASH') { foreach $k (sort keys %{$array[$i]{$j}}) { push(@s, sprintf("(%2d) %-6s->%-6s => ", $i, $j, $k). $array[$i]{$j}{$k}); } } else { push(@s, sprintf("(%2d) %-6s => ", $i, $j). $array[$i]{$j}); } } push(@s, ""); } open(OUT, "> $f") or die("open error $f"); foreach (@s) { print $_. "\n"; print OUT $_. "\n"; } close(OUT); } __END__; -----$ load_db.pl $----- > WEB上で入力、閲覧ができるシステムを作るわけですが、サーバーも必要ですよね?そのときはレンタルサーバーとなってしまうのでしょうか? そうですね。自力でサーバーを構築するのはそれほど難しく無いですが、それを維持するのは大変なので、レンタルサーバーを利用するのが良いと思います。 > 私が借りているどめいん屋にはそういうサービスがないようなので、そこから考えなくてはいけませんでした。 僕は、そのサービスを知らないので、どの程度のスペックか不明ですが。。。 個人向けとしては、XREAが一押しです。ドメイン(com/net/org/biz/info/name)を取得しても、年間3390円と格安でRDBもMySQL, PostgreSQLが使えて、ディスク容量も1GB。転送容量も十分あります。 ただし、基本的にサポートはあてにせず、問題を自力で解決できる人向け。と言うサービスであるのと、個人向けサービスであって、企業向けでは無い。(と、言いつつXREAを使って企業向けサイトを複数設置した実績がありますが。)ので、Scotty_99様の目的にあうかどうか微妙ですが。 アクセス数やその内容にも寄るとは思いますが、共用サーバーより、高くても専用サーバーをレンタルして、root権もご自分で握っていた方が良いのかも知れません。(その分、プログラムのバージョンアップも自分で行う様ですが。) 5000PV/日程度であればXREAでも十分絶えられます。 もし、XREAの様なサーバーを利用するなら、素直にSQLを使った方が良い様な気もします。 不明点があれば、また質問してください。(ただし、休みは明日までなので、明後日以降レスポンスは落ち気味になると思いますが。)

Scotty_99
質問者

お礼

有益な回答ありがとうございました。 >BerkeleyDBの取り扱いはそれほど難しい物ではありません。 Perlで趣味でプログラムしてきましたが、ちゃんとわかってやっていないと自分でもわかっていましたので、回答くださった内容は理解できない部分も多々ありました。自分にできるかというと、一から作るのはできなさそうです。ほかのDBでも同じようなコーディングメインの作業になりますよね。ACCESS感覚でWEBアプリが構築できればよいのですが、もしご存知であれば教えてください。 私が利用しているどめいん屋ではMySQLが利用できるそうです。ただ、むずかしそうです。本を買ってできそうか見てみようと思います。

  • Dpop
  • ベストアンサー率51% (279/544)
回答No.3

Web屋です。 1つの方法として、BerkeleyDBを利用する。と言う方法もあります。 ハッシュをtieで関係づけ(ハッシュである必要は無いのですが、データベースとして利用する場合、ハッシュが一番都合が良い。)、ハッシュのやりとりをするだけでBerkeleyDBへアクセスした事になります。 ハッシュなので、ロック系はメモリ上の保護だけを行えば問題ありません。具体的には、同時に同じハッシュへ書き換えができない様に制御するだけです。(フラグを立てるなどすれば良いです。) ちなみに。テキストファイルへのアクセスでも、同時に書き込まない様に制御する事はできます。ただ、面倒だし時間が係る。と言うだけの事です。(利用者から見て、ややレスポンスが遅く見える。) しかし、プログラムの異常終了の事を考えると、テキストファイルよりはBerkeleyDBの方が安全かな。。。と言う気がします。 MLDBMと言うパッケージと組み合わせれば、複雑なデータ構造もBerkeleyDBへ格納する事が可能です。

Scotty_99
質問者

お礼

回答ありがとうございました。 >ハッシュのやりとりをするだけでBerkeleyDBへアクセスした事になります ハッシュはわかりますが、お言葉が理解できませんでした。BerkeleyDBとやらは簡単なのでしょうか? 私が作ったのはyahooのようにマイページ機能がついたユーザ管理CGIです。 いまは時間がないのでテキストファイル版で仕事しますが、そのうちにDBに移行したいです。WEB上で入力、閲覧ができるシステムを作るわけですが、サーバーも必要ですよね?そのときはレンタルサーバーとなってしまうのでしょうか?私が借りているどめいん屋にはそういうサービスがないようなので、そこから考えなくてはいけませんでした。

回答No.2

>SQLサーバーなどを使わないで多人数(~10人程度)が >利用するプログラムはテキストファイルが壊れやすい >でしょうか? 排他制御をきっちり行えば、壊れることはないはずですが、 プログラムが何らかの理由でコケた場合など、想定外の 事態の際に、壊れる危険はあると考えた方が良いと思います。 RDBを使うと、例外時の動作についても、ロールバックなど 適切な対応が行われますし、排他制御などが手軽にできて 楽できます。 逆に面倒な思いをすれば、RDBを使わなくても、ファイルが壊れない 共有処理は可能であると思います。 >#1 >テキストファイルは更新という処理はできません。 >更新時は全部上書きし直します。 >つまり削除して新規に追加するイメージです。 ストリーム入出力のような操作を前提に考えると、 書き換えは不可能ですが・・ DISK上のテキストファイルであれば、ランダムアクセスも データの書き換えも可能なハズですよ? 一般的には、テキストファイル=可変長レコードですので、 ・ランダムにアクセスするのが難しい。 ・データ長の変わる書き換えは不可能。 という悩みがあるかと思いますが。

Scotty_99
質問者

お礼

回答ありがとうございました。DBはアクセスを使って作れる方法を模索しています。というのは、すでにBDだけは作成済みだからです。あと、テキストファイルを使ったデータベースもほぼ完成しました。これをDBに移植できればと思うのですが、なかなかむずかしいようです。

  • nonosuke
  • ベストアンサー率25% (41/162)
回答No.1

汎用機系の知識は豊富なのですが、パソコンには疎いので誤っているかもしれませんということを先に断っておきます。 テキストファイルは更新という処理はできません。更新時は全部上書きし直します。つまり削除して新規に追加するイメージです。 更新時に排他が正しく行われていない場合、ファイルを壊れることは確実です。 データベースによる管理が必要ではないでしょうか? PostgreSQLというDBMSはどうですか? 最近Unixを触るようになり、PostgreSQLを使ってますが、フリーではありますが、DBMSとして充分に使えるものです。 Windows版はあまり品質が良くないという話を聞いてましたが、最近は使える代物になったようです。 良くPHP+PostgreSQLという組み合わせを聞きます。(書籍も多く出版されてますね) Oracle、DB2より軽そうでなかなかいいと思いますが...

Scotty_99
質問者

お礼

回答ありがとうございました。PostgreSQLは名前は知っていましたが、WEBで調べたところすぐには修得できなさそうです。本屋で調べてみますが、コーディングする自信がありません。