質問: `Qt`で開発をしている者です。 **質問の動機** 例えば、大量のウィジェットが存在しており、そのウィジェットごとにデータが格納されているとします。極端な話、そのウィジェット毎に、保存データのファイルを作成するのは、処理としてはあり得ない方法でしょうか? というのは、アプリを立ち上げた際に、一気にロードをするのではなくて、GUI上の何らかのアクションが生じた時に、そのウィジェットに対応したものを、その都度それに応じたファイルをロードするようにしたらいいのではないかと考えました。 今までは全ての情報を、シーケンスで一つ~三つのファイルにまとめてそれを取り出したいデータごとに吸い出していました。 a,b,cというファイルを、ひとつのアプリで、aのファイルを選べばaのデータが、bを選べばbのデータが、cを選べばcのデータがそれぞれ吸い出されるようにしていたのです。 しかし、今回、aをさらに分割し、aというデータが保持しているウィジェット1についての情報を、a-1ファイルへ、ウィジェット2についての情報をa-2ファイルへと、個別化してみたいと考えています。同様に、bが持っているウィジェット1についての情報は、b-1ファイルへ、以下略。 ただ分割しまくるというのは、危険な行為のように思えてしまいます。自分には、ファイルは多くても三~四という先入観があり、`open`と`close`を繰り返し、後は名前に番号さえ入れてやれば、理論上は大量に増やせるのはわかります。 データの永続化については保存と取り出しが出来ただけで感動していたのですが、かなり大切な部分だという意識が高まってきました。(お答え次第によってはすぐにしぼんでしまうかもしれませんが) **聞きたいこと** プロフェッショナルな方達からすると、ファイルは用途に応じていくらでも作ったほうがよいのでしょうか?それとも、できるだけ少なくした方がよいでしょうか?ものの本などを見ても、ファイルの作り方、取り出し方などはよくみるのですが、 「**一つのアプリの、あるデータが保持しているすべての情報に対して、その情報を一定のルール区切り毎に(1000のウィジェットが保有しているデータなら1000のファイルを)分割して、その数だけ作成する事**」 は、worseな選択肢でしょうか。データベースはあまり利用したくないです。 ちなみに多分多くとも100~300になろうと思いますが、場合によってはファイルの量が増えすぎて、検索に支障が出て、かえって時間がかかったりしてしまいそうな気がしています。これはやめておいたほうがいいでしょうか? --- **ぼやき:seekについて** ひょっとして、こういうことをしないで済むために、ファイルを全部読み込むことなく、部分的な高速アクセスを図る方法が、`seek`というものなのでしょうか?一回一回分割したファイルにアクセスするのではなく、特定のseek位置へ移動してから読み込むべきということでしょうか。File系列の話の際には、よく見るメソッドですけれども、今まで利用する機会がありませんでした。 こちらが使えるのならば、こちらを検討した方がいいでしょうか?よく使い方がわかりませんが、QFileも、保持中のデータをマップ化して、オフセット指定をして特定のデータのみにアクセスできるという方法があると耳にしたことがあります。こちらを検討したほうがいいかなぁともかんがえています。公式を見ているのですが、ランダムアクセスサポートという事で、大きな間違いではなさそうです。しかし、`QDataStream`で登録しているのに、`QIODevice`しか`[seek][3]`メソッドはないし・・・。いろんなものがごぎゃまぜになっているデータのなかから`seek`するというのも、試さず嫌いで敬遠していました。質問も質問としてまとまる気にならず、実際自分は、`QFile`,`QIODevice`,`QDataStream`,`QTextStream`,`python`に引き直すと、`open()`,`io()`,`pickle()`?等の明確な違いがあまりわからず、教科書通りに処理していました。 **ぼやきのあとで** 今改めて考えてみますと、`file`は、データが入っているポイントを探し当てる物。そしてそれにに焦点を当てるためのクラス。`io`系のメソッドは取り出された一枚のデータが書かれているシートを走査して、情報を書き込んだり、読み取るための、ある意味コピー機のフラッシュのような役目。次に、`pickle`等は、`io`がよみとった情報を、バイトコードやテキストファイルに変換し、`file`に埋め込む役目をしているという理解で問題ないでしょうか?とすると、`io`が`seek`メソッドをもつというのもわかります。しかし、`seek`は、`io`という段階にありながらも、情報をよみとれるというのがいまいちピンときません。読み取る相手がバイト列か単なるテキスト文字列かは、Dataの種類によって異なる気も致します。 初心者の頃からもやもやしてました。 **聞きたいこと2** **聞きたいこと**で聞いたことを代わりに行うのがseekメソッドなのでしょうか? `file`と、`io`,そして`pickle`等の永続化3点セットの関係性を、氷解させてくれるようないい説明、たとえ噺などはございませんか? --- **まとめ** まとめると、自分のやろうとしているのは、`file`のような、データの入っている箱を選ぶ段階で、個別具体的にするべきか?あるいは、データの入っている箱を選ぶ段階ではなく、その箱を見付けた後で、その箱の中から都合の良いデータを選ぶ処理をするべきか?という話に要約されるのではないかなとおもうようになりました。一言でいうと、このような疑問になりますが、どなたか詳しい方おねがいいたします。 --- ``` python 3.6.5 Pyside 1.2.4 ```
回答: ファイルにデータを保存するというのは、管理者以外からの入力がないという条件であれば有力な方法です。Qtで開発しているということはデスクトップアプリで、データベースはあまり利用したくないということはこの条件に該当すると思います。こういうケースでは、MySQLをインストールするのは手間です。それに、ファイルだとエディタで簡単に修正できるし、gitで履歴管理もできます。 データを約10万件のファイルにしてlinuxサーバーで実際に運用していますが、処理時間は以下のようなもので、処理が単純なだけデータベースを使うより速いです。2回同じコマンドを入力しているのは、1回目はリブートしてキャッシュがなされていない場合で、2回目はキャッシュされている場合です。 ``` niji@data1:/var/cache/weather$ time ls -U meta | wc -l 118578 cdreal 0m0.510s user 0m0.041s sys 0m0.463s niji@data1:/var/cache/weather$ time ls -U meta | wc -l 118578 real 0m0.086s user 0m0.042s sys 0m0.055s niji@data1:/var/cache/weather$ time od -x meta/T06842.json real 0m0.005s user 0m0.000s sys 0m0.002s niji@data1:/var/cache/weather$ time od -x meta/T06842.json real 0m0.002s user 0m0.002s sys 0m0.000s ``` ファイルは必要であれば、必要なだけ作ったらいいと思います。10万個であれば何の問題もないし100万個になっても`ls`が使いづらくなるぐらいで処理速度自体は問題はないです。それに、ひとつのフォルダのファイル数が多くなりすぎれば階層化すればいいだけの話です。 なお、1つのdatabaseを元にしてmany fileをアップデート毎に作れるようにしておくのが最適という意見もありますが、少数のfileで管理しておいて実行用のmany fileをアップデート毎に作るのも可能で、必ずしもdatabaseにする必要はないし、大量に一括で処理する場合はdatabaseよりもfileベースの方が処理が速いケースも多いです。 **聞きたいこと2について** pythonの`pickle`は非常に高速です。Qiitaで「C#のLinqを使っているのならPythonの方が2倍速くなる」という記事を書いた時に測ったら、全件のデータがほしいのならデータベースを使うより20倍以上速いという結果になりました。Pythonの場合は、データを保存する必要があれば`pickle`で保存ということを基本にして間違いないと思います。メモリーもディスクも十分な容量が使える時代にわざわざ手間のかかる`seek`を使うことはあまりないと思います。