46801


`Qt`で開発をしている者です。  
**質問の動機**  
例えば、大量のウィジェットが存在しており、その[ウィジェット](http://e-words.jp/w/%E3%82%A6%E3%82%A3%E3%82%B8%E3%82%A7%E3%83%83%E3%83%88.html)ごとにデータが格納されているとします。極端な話、そのウィジェット毎に、保存データのファイルを作成するのは、処理としてはあり得ない方法でしょうか？  
というのは、アプリを立ち上げた際に、一気にロードをするのではなくて、GUI上の何らかのアクションが生じた時に、そのウィジェットに対応したものを、その都度それに応じたファイルをロードするようにしたらいいのではないかと考えました。  
今までは全ての情報を、シーケンスで一つ～三つのファイルにまとめてそれを取り出したいデータごとに吸い出していました。  
a,b,cというファイルを、ひとつのアプリで、aのファイルを選べばaのデータが、bを選べばbのデータが、cを選べばcのデータがそれぞれ吸い出されるようにしていたのです。  
しかし、今回、aをさらに分割し、aというデータが保持しているウィジェット１についての情報を、a-1ファイルへ、ウィジェット２についての情報をa-2ファイルへと、個別化してみたいと考えています。同様に、bが持っているウィジェット１についての情報は、b-1ファイルへ、以下略。  
  
ただ分割しまくるというのは、危険な行為のように思えてしまいます。自分には、ファイルは多くても三～四という先入観があり、`open`と`close`を繰り返し、後は名前に番号さえ入れてやれば、理論上は大量に増やせるのはわかります。

データの永続化については保存と取り出しが出来ただけで感動していたのですが、かなり大切な部分だという意識が高まってきました。(お答え次第によってはすぐにしぼんでしまうかもしれませんが)  
**聞きたいこと**  
プロフェッショナルな方達からすると、ファイルは用途に応じていくらでも作ったほうがよいのでしょうか？それとも、できるだけ少なくした方がよいでしょうか？ものの本などを見ても、ファイルの作り方、取り出し方などはよくみるのですが、

「
**一つのアプリの、あるデータが保持しているすべての情報に対して、その情報を一定のルール区切り毎に（１０００のウィジェットが保有しているデータなら１０００のファイルを）分割して、その数だけ作成する事**
」

は、worseな選択肢でしょうか。データベースはあまり利用したくないです。  
ちなみに多分多くとも100~300になろうと思いますが、場合によってはファイルの量が増えすぎて、検索に支障が出て、かえって時間がかかったりしてしまいそうな気がしています。これはやめておいたほうがいいでしょうか？

* * *

**ぼやき：seekについて**  
ひょっとして、こういうことをしないで済むために、ファイルを全部読み込むことなく、部分的な高速アクセスを図る方法が、`seek`というものなのでしょうか？一回一回分割したファイルにアクセスするのではなく、特定のseek位置へ移動してから読み込むべきということでしょうか。File系列の話の際には、よく見るメソッドですけれども、今まで利用する機会がありませんでした。  
こちらが使えるのならば、こちらを検討した方がいいでしょうか？よく使い方がわかりませんが、QFileも、保持中のデータをマップ化して、オフセット指定をして特定のデータのみにアクセスできるという方法があると耳にしたことがあります。こちらを検討したほうがいいかなぁともかんがえています。[公式](https://docs.python.jp/3/library/io.html?highlight=seek#io.IOBase.seek)を見ているのですが、ランダムアクセスサポートという事で、大きな間違いではなさそうです。しかし、`QDataStream`で登録しているのに、`QIODevice`しか`[seek][3]`メソッドはないし・・・。いろんなものがごぎゃまぜになっているデータのなかから`seek`するというのも、試さず嫌いで敬遠していました。質問も質問としてまとまる気にならず、実際自分は、`QFile`,`QIODevice`,`QDataStream`,`QTextStream`,`python`に引き直すと、`open()`,`io()`,`pickle()`?等の明確な違いがあまりわからず、教科書通りに処理していました。  
  
**ぼやきのあとで**  
今改めて考えてみますと、`file`は、データが入っているポイントを探し当てる物。そしてそれにに焦点を当てるためのクラス。`io`系のメソッドは取り出された一枚のデータが書かれているシートを走査して、情報を書き込んだり、読み取るための、ある意味コピー機のフラッシュのような役目。次に、`pickle`等は、`io`がよみとった情報を、バイトコードやテキストファイルに変換し、`file`に埋め込む役目をしているという理解で問題ないでしょうか？とすると、`io`が`seek`メソッドをもつというのもわかります。しかし、`seek`は、`io`という段階にありながらも、情報をよみとれるというのがいまいちピンときません。読み取る相手がバイト列か単なるテキスト文字列かは、Dataの種類によって異なる気も致します。  
初心者の頃からもやもやしてました。

**聞きたいこと２**  
**聞きたいこと** で聞いたことを代わりに行うのがseekメソッドなのでしょうか？  
`file`と、`io`,そして`pickle`等の永続化3点セットの関係性を、氷解させてくれるようないい説明、たとえ噺などはございませんか？

* * *

**まとめ**  
まとめると、自分のやろうとしているのは、`file`のような、データの入っている箱を選ぶ段階で、個別具体的にするべきか？あるいは、データの入っている箱を選ぶ段階ではなく、その箱を見付けた後で、その箱の中から都合の良いデータを選ぶ処理をするべきか？という話に要約されるのではないかなとおもうようになりました。一言でいうと、このような疑問になりますが、どなたか詳しい方おねがいいたします。

* * *
[code]

    python 3.6.5 Pyside 1.2.4
    
[/code]


CC BY-SA 4.0
2018-07-20T06:54:48.150
46773
2018-07-21T09:25:41.507
24284
question
python pyqt pyside file
fileをデータごとに作り出すことはベストプラクティスか？file,io,pickle系処理の関係性とは？


似たようなことを考えたことがありますが、基本的にこういう案件ではデータベースを使用するほうが良い結果が得られると思います。下記ではいくつかの項目について確認していきます。

### アクセス特性

アクセスには大きく分けてシーケンシャルアクセス(つまりファイルの最初から最後まで読み取る)とランダムアクセス(ある特定の部位のみを読み取る)という方法があると思います。  
ファイルは原則としてシーケンシャルアクセスにしか向いていません。設問者の言う通りseekメソッドはファイルにおけるランダムアクセスを可能としますが、そのメソッドはどのバイトから読みだすかというバイト単位でしか指定できません。これでは実際のアプリケーションを作るときに非常に困ったことになるでしょう。(例えばウィジェットBはファイルfaを65536byteからseekし32768byteだけ読みだすとプログラミングできなくもないですが、ファイルのバイト数がずれただけでこのプログラムは破綻します)。つまりseekメソッドでは実用的なクエリ(必要なデータを抽出する)ということに向きません。不可能とまでは言わないですが制御が大変です。

### many file vs 1 file vs database

我々がデータ管理として取りうるアプローチとしては、many
fileか1fileかdatabaseなのですが、1fileというのは上記のファイルの特性から、遅延してロードするとかの用途にあまり向いていません。(ランダムアクセスが不便なので遅延してロードするには向かない。)  
次に問題となるのが、どのタイミングでクエリ(つまりどのウィジェットにどのデータを割り当てるかを仕分ける作業)を行うかです。事前にmany
fileに分割しておけば、アプリケーション実行時にクエリを実行する必要がないので高速でしょう。高速なアプリケーションを作るならばmany
fileは処理の最適化として機能すると思います。しかしデータが複数のファイルに分断されます。  
データが複数に分断することが危険であると設問者も指摘していますが、何が危険なのでしょうか？データの管理が手間になります。共有可能なデータもすべて分断されますし、プログラムのアップデート毎にデータの整合性に神経を使うことになります。  
そのような課題を解決するために世の中にdatabaseというものが存在しています。databaseにできて1fileにできないこと、それはインデックスによるランダムアクセスが可能だということです。例えばウィジェットAに使用したいデータ範囲をdatabaseに定義してインデックスを使用すれば、そのウィジェットに必要なデータのみを抽出するということが簡単かつ高速に行うことができます。当然ながらデータベースがあれば、事前にクエリを発行することでmany
fileを簡単に生成しておくこともできます。逆にmany
fileからdatabaseを構築することは手間がかかります。結論としては整合性のとれた1つのdatabaseを元にしてmany
fileをアップデート毎に作れるようにしておくのが最適かと。

下記はデータベース(SQL)に関する参考文献です。  
<https://use-the-index-luke.com/ja>

### 聞きたいこと2について

pythonのfileは、HDDに格納されているファイルにアクセスするためのオブジェクト。通常はpythonのioと連動してファイルに対してシーケンシャルにアクセスする。  
pythonのioは、データをストリーム(≒シーケンシャルアクセス的な読み書きを行えるオブジェクト)として扱うためのもの。.seekメソッドという頭出しのような機能もあるがおまけです。  
pythonのpickleは、pythonが扱えるオブジェクトを高速にローディングし効率的に圧縮できるようにバイナリ化したファイルのこと。pythonを使うなら通常のfileよりもpickleのほうが断然速いのでおすすめです。databaseは使わずに1fileだけで処理したいのならば、まずはpickle化することを検討したほうがいいかもしれないですね。(アプリケーションのスタートアップ時に読み込んで、あとはそのデータをウィジェットに配給するプログラムを書くイメージ)

pythonの先生に見せたら怒られるかもしれませんが、上記のようなイメージでそれほど外れていないはずです。


CC BY-SA 4.0
2018-07-21T01:37:49.373
46799
2018-07-21T01:37:49.373
25980
46773
answer


ファイルにデータを保存するというのは、管理者以外からの入力がないという条件であれば有力な方法です。Qtで開発しているということはデスクトップアプリで、データベースはあまり利用したくないということはこの条件に該当すると思います。こういうケースでは、MySQLをインストールするのは手間です。それに、ファイルだとエディタで簡単に修正できるし、gitで履歴管理もできます。

データを約10万件のファイルにしてlinuxサーバーで実際に運用していますが、処理時間は以下のようなもので、処理が単純なだけデータベースを使うより速いです。2回同じコマンドを入力しているのは、1回目はリブートしてキャッシュがなされていない場合で、2回目はキャッシュされている場合です。

[code]

    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
    
[/code]

ファイルは必要であれば、必要なだけ作ったらいいと思います。10万個であれば何の問題もないし100万個になっても`ls`が使いづらくなるぐらいで処理速度自体は問題はないです。それに、ひとつのフォルダのファイル数が多くなりすぎれば階層化すればいいだけの話です。

なお、1つのdatabaseを元にしてmany
fileをアップデート毎に作れるようにしておくのが最適という意見もありますが、少数のfileで管理しておいて実行用のmany
fileをアップデート毎に作るのも可能で、必ずしもdatabaseにする必要はないし、大量に一括で処理する場合はdatabaseよりもfileベースの方が処理が速いケースも多いです。

**聞きたいこと2について**

pythonの`pickle`は非常に高速です。Qiitaで「[C#のLinqを使っているのならPythonの方が2倍速くなる](https://qiita.com/yniji/items/6585011633289a257888)」という記事を書いた時に測ったら、全件のデータがほしいのならデータベースを使うより20倍以上速いという結果になりました。Pythonの場合は、データを保存する必要があれば`pickle`で保存ということを基本にして間違いないと思います。メモリーもディスクも十分な容量が使える時代にわざわざ手間のかかる`seek`を使うことはあまりないと思います。


CC BY-SA 4.0
2018-07-21T04:33:44.857
46801
2018-07-21T09:25:41.507
2018-07-21T09:25:41.507
15171
15171
46773
answer