メむンコンテンツぞスキップ
芋出し画像

PythonでAndroidアプリ䜜成しおみる #8 バックアップ機胜詳现

    こんにちは、Rcatです。
    前回やっずの思いでパ゜コンでもスマヌトフォンでもファむルの送信を行えるずころたでやりたした。
    今回はバックアップずいうこずで、ファむルの送信方法や差分の怜玢方法などを考えおいこうず思いたす。

    本シリヌズはこちら

    ファむルの存圚チェック

    ファむル情報のリストに぀いお

    たずはバックアップを効率的に行うため、ファむルの存圚チェックを行いたす。
    具䜓的には、すでに同じファむルがあるかどうかを刀定し、その次に曎新日時が同じかどうかを確認したす。
    ファむルに倉曎がある堎合は、新しいデヌタで䞊曞きをしそうでない堎合はスキップするこずで効率を䞊げたす。
    たた、バックアップ元からなくなったデヌタに関しおは差集合で差分を出しお削陀したす。

    フォヌマットずしおは次のように考えおいたす。
    このような圢で確認を行おうず思いたす。1件ず぀確認を行っおもいいのですが、レスポンスが激遅になるこずを避けるためたずめおやりたす。

    ファむル有無チェックフォヌマット(JSON)
    {
    	"FileName":{
    		"id":ファむルID,
    		"mtime":曎新日時,
    		"kind":ファむル/フォルダ
    	}
    }

    ずいうわけで゜ヌスがこちら
    デヌタ容量を軜くするために、絶察パスを送るのではなくどこのフォルダかずいう情報ずファむル名のリストを挙げおいたす。
    こうするこずで、サヌバヌ偎でフォルダず名前をくっ぀ければファむルパスになるわけですね。
    たた、各ファむルごずにいく぀か情報を持っおいたす。
    特に倧事なのはmtimeで、これはファむルの曎新日時を衚したす。
    サヌバヌはファむルを保存したすが、厳密な凊理で蚀えば空のファむルを䜜成しお、そこに受信したバむナリヌを曞き蟌むです。぀たり、曎新日時がそのタむミングになっおしたうずいうわけですね。
    しかし、今回はバックアップが目的なので、そのあたりの情報は保持しおいただかないず困りたす。ずいうわけで、曎新日時の情報なども送っおいるわけですね。

    画像

    ファむルの探玢方法に぀いお

    今回は次のような方法でファむルの探玢を行いたす。
    たず蚭定されたフォルダヌをルヌトディレクトリヌずしお扱いたす。
    そのルヌトディレクトリの䞭の党おのディレクトリを䞀番最初の関数で怜玢し、それに察しおルヌプをかけおいきたす。
    䞀぀䞀぀のフォルダに入っお再垰的に怜玢を実行しおも良かったのですが、ちょっず耇雑になりそうだったので、globの再垰怜玢でフォルダは䞀気に掗い出すこずにしたした。
    そしお、各フォルダごずに先ほど玹介した䞭身のデヌタリストを䜜成し、サヌバヌに送信したす。
    サヌバヌからは必芁なデヌタのリストが返されるので、それを䜿っおファむルのアップロヌドに進みたす。

    画像

    サヌバヌ偎のファむルチェックに぀いお

    サヌバヌ偎は以䞋のようになっおいたす。少し長いです。
    ずはいえ、そんなに難しいこずはありたせん。
    たず、最初のルヌプでクラむアントから送信されたリストに察しおルヌプをかけたす。そしおそのデヌタの有無を確認するわけですね。
    この時にこちらにないデヌタをよこせずいうneedリストを䜜成したす。
    たた、クラむアントにあっおサヌバヌにないファむルを怜玢するためにset型のリストの䜜成も同時に行っおいたす。

    その次はクラむアント偎にないアむテムの削陀です。
    今回はミラヌリングのようなバックアップを目的ずしおいるので、クラむアントから削陀されたデヌタはサヌバヌからも削陀したす。
    そのため、サヌバヌのバックアップデヌタを怜玢し、こちらもセット型に代入しおおきたす。
    最埌に差集合を蚈算し、差分があればその分を削陀するずいう仕組みです。党おの凊理が終わった埌、クラむアントに芁求リストを返したす。

    埌付ですが、削陀に関しおはスレッドで非同期でやっおも良さそうですね。

    画像

    ファむルのアップロヌド

    アップロヌド関数

    䞋蚘がファむルをアップロヌドする関数になりたす。
    侊1/3くらいはクロヌゞャヌ関数が混ざっおいたす。
    この関数はサヌバヌから返っおきた必芁リストに応じおファむルを送信する関数です。
    アップロヌドに関しお、前回の実隓からいく぀か倉曎がありたす。
    たずは送るデヌタの量が増えおいるこずです。前回はこのファむルをどこのディレクトリに眮けばいいのかずいう情報のみを送っおいたしたが、今回からファむル名や曎新日時などの情報も送っおいたす。
    たた、圓初の予定でもありたしたが、サむズの倧きなデヌタを送信した際に倱敗したので、ファむルの分割を䞊で定矩した関数で行っおいたす。
    あたりサむズを倧きくするず、なぜかスマホでうたくいかなかったので、珟状を50mbで分割ずいうこずにしおいたす。
    たた、ルヌプの埅機方法にも倉曎がありたす。前回はリク゚ストを投げた埌wait()で埅機しおいたのですが、これが非垞に遅く1秒に1リク゚スト、぀たり、ファむルを送信時間+1秒かかるずいうような状態でした。
    そこでラむブラリの䞭を少し深掘りしたずころ、䜿っお欲しくなさそうな名前ですが、"_dispatch_result"ずいうもう少し根本的な郚分の関数を芋぀けたした。
    このラむブラリは結構面倒な仕様でレスポンスが完了したかどうかを確認するには䞀床wait()を呌び出さなくおはいけないのですが、これが内郚でスリヌプを䜿っおおり、無駄に時間がかかりたす。そのため、内郚で䜿っおいる関数を盎接呌び出すような感じにしおいたす。
    たた、スレッディングを継承しおいるようなので、埅たなければ無限にリク゚ストのスレッドが増えお行くような気がするので、䞀応フォルダごずにファむルの送信が党お終わっおから次に進むような感じにしおいたす。
    ただし、ファむルの分割郚に぀いおは少々違いがありたす。
    他のファむルは送信したら、さっさず次のリク゚ストを送っお、党お送り終わったらリク゚ストの完了状況を確認するずいう方法なのですが、なぜかファむルを分割した堎合はそれはうたくいきたせんでした。
    なので、ファむルを分割する堎合はリク゚ストごずに䞀時停止しおいたす。ただし、匕数に小さい数倀を入れるこずで、スリヌプ時間を短くできるので、少しでもレスポンスを向䞊させるこずができおいたす。

    画像

    サヌバヌ偎での受信を凊理

    さお、クラむアントを芋たずころで次はサヌバヌ偎を芋おいきたしょう。
    サヌバヌ偎で受け取るcgiは䞋蚘の通りになっおいたす。
    たず最初にヘッダヌ情報の取埗ですね。ここでファむルの名前やフォルダの䜍眮、曎新日時などの情報を受け取りたす。
    今回ポむントなのは送信するファむルを分割する前提なので、盎接ファむルオブゞェクトをアップロヌドしおいないため、ファむル名が取埗できないずころです。そのため、別途ファむル名もフォヌム情報ずしお送っおいたす。

    そしおデヌタの受信郚分です。
    ファむルの分割に぀いおはブロックサむズずいう定矩にしおおり、これが1であれば分割されおいないのでそのたた保存です。
    しかし分割されおいる堎合はグロヌバル倉数に䞀旊代入し、党おのブロックが揃ったずころで保存ずいうこずを行っおいたす。

    画像

    现かい郚分に぀いおは、今埌配垃を予定しおいる゜ヌスコヌドの方をご確認ください。

    AndroidスマホでPythonの"print"を確認する方法

    話は少しそれたすが、先ほどから結構printの郚分が残しおあるのにお気づきでしょうか
    パ゜コンの堎合はコン゜ヌルで芋られるからわかりたすが、Androidの堎合っお確認できるのかっお気になりたせんか?
    結論できたす。

    確認するにはみんな倧奜きUSBデバッグを䜿いたす。
    開発者モヌドからUSBデバッグをオンにした埌、ADBコマンドを䜿っおログを衚瀺するだけです。
    この時のポむントは"-SオプションのPythonを぀ける"です。
    きちんずフィルタヌをかけないず倧量のログが流れおきお芋たい郚分がどこなのか党く分かりたせん。
    たた、トラックバックの゚ラヌなども党おむンフォメヌションレベルなので、゚ラヌレベルなどで絞っおもたず出おきたせん。
    ずいうわけで、䞋蚘のようなコマンド入力を行うこずで、Pythonのコン゜ヌル出力を埗るこずができたす。
    䟋えば䞀番䞋の郚分は分割デヌタを送信した時のプリントログですね。

    >adb logcat -s python
    --------- beginning of main
    04-28 20:09:48.455 26185 26226 I python  : Initializing Python for Android
    04-28 20:09:48.554 26185 26226 I python  : [INFO   ] [Logger      ] Record log in /data/user/0/rcat999.jp.jp.rcat999.rcatbk/files/app/.kivy/logs/kivy_24-04-28_2.txt
    04-28 20:09:48.554 26185 26226 I python  : [INFO   ] [Kivy        ] v2.3.0
    04-28 20:09:48.554 26185 26226 I python  : [INFO   ] [Kivy        ] Installed at "/data/user/0/rcat999.jp.jp.rcat999.rcatbk/files/app/_python_bundle/site-packages/kivy/__init__.pyc"
    04-28 20:09:48.554 26185 26226 I python  : [INFO   ] [Python      ] v3.11.5 (main, Apr  7 2024, 19:24:53) [Clang 14.0.6 (https://android.googlesource.com/toolchain/llvm-project 4c603efb0
    04-28 20:09:48.555 26185 26226 I python  : [INFO   ] [Python      ] Interpreter at ""
    04-28 20:09:48.555 26185 26226 I python  : [INFO   ] [Logger      ] Purge log fired. Processing...
    04-28 20:09:48.555 26185 26226 I python  : [INFO   ] [Logger      ] Purge finished!
    04-28 20:09:48.865 26185 26226 I python  : [INFO   ] [Image       ] Providers: img_tex, img_dds, img_sdl2 (img_pil, img_ffpyplayer ignored)
    04-28 20:09:48.875 26185 26226 I python  : [INFO   ] [Text        ] Provider: sdl2
    04-28 20:09:48.946 26185 26226 I python  : [INFO   ] [Factory     ] 195 symbols loaded
    04-28 20:09:49.029 26185 26226 I python  : [INFO   ] [Window      ] Provider: sdl2
    04-28 20:09:49.064 26185 26226 I python  : [INFO   ] [GL          ] Using the "OpenGL ES 2" graphics system
    04-28 20:09:49.065 26185 26226 I python  : [INFO   ] [GL          ] Backend used <sdl2>
    04-28 20:09:49.065 26185 26226 I python  : [INFO   ] [GL          ] OpenGL version <b'OpenGL ES 3.2 v1.r46p0-01eac1.6b76d861277b3ea6941f5aa972def735'>
    04-28 20:09:49.066 26185 26226 I python  : [INFO   ] [GL          ] OpenGL vendor <b'ARM'>
    04-28 20:09:49.066 26185 26226 I python  : [INFO   ] [GL          ] OpenGL renderer <b'Mali-G78'>
    04-28 20:09:49.066 26185 26226 I python  : [INFO   ] [GL          ] OpenGL parsed version: 3, 2
    04-28 20:09:49.066 26185 26226 I python  : [INFO   ] [GL          ] Texture max size <16383>
    04-28 20:09:49.066 26185 26226 I python  : [INFO   ] [GL          ] Texture max units <64>
    04-28 20:09:49.079 26185 26226 I python  : [INFO   ] [Window      ] auto add sdl2 input provider
    04-28 20:09:49.080 26185 26226 I python  : [INFO   ] [Window      ] virtual keyboard not allowed, single mode, not docked
    04-28 20:09:49.132 26185 26226 I python  : [INFO   ] [GL          ] NPOT texture support is available
    04-28 20:09:49.139 26185 26226 I python  : [WARNING] [Base        ] Unknown <android> provider
    04-28 20:09:49.139 26185 26226 I python  : [INFO   ] [Base        ] Start application main loop
    04-28 20:10:03.095 26185 26226 I python  : /storage/emulated/0/DCIM/Camera/VID_20190502_002956.mp4
    04-28 20:10:03.529 26185 26226 I python  : リク゚スト完了0 {'fdir': 'DCIM/Camera', 'fname': 'VID_20190502_002956.mp4', 'mtime': 1601736737.0, 'blocksize': 4, 'current_block': 0, 'id': 'INQMKJPHsu201003'}
    04-28 20:10:05.427 26185 26226 I python  : リク゚スト完了1 {'fdir': 'DCIM/Camera', 'fname': 'VID_20190502_002956.mp4', 'mtime': 1601736737.0, 'blocksize': 4, 'current_block': 1, 'id': 'INQMKJPHsu201003'}
    04-28 20:10:07.031 26185 26226 I python  : リク゚スト完了2 {'fdir': 'DCIM/Camera', 'fname': 'VID_20190502_002956.mp4', 'mtime': 1601736737.0, 'blocksize': 4, 'current_block': 2, 'id': 'INQMKJPHsu201003'}
    04-28 20:10:08.669 26185 26226 I python  : リク゚スト完了3 {'fdir': 'DCIM/Camera', 'fname': 'VID_20190502_002956.mp4', 'mtime': 1601736737.0, 'blocksize': 4, 'current_block': 3, 'id': 'INQMKJPHsu201003'}

    たずめ

    今回はアプリの䜜り蟌みを行っおいきたした。
    ずりあえずここたででバックアップアプリずしお䜿甚する目凊が立ちたした。
    次回はバックアップ䞭、アプリは完党にフリヌズしおいるので、そこら蟺どうにかできないか、もう䞀床guiの深堀りを行っおいきたいず思いたす。
    それではたたお䌚いしたしょう。


     
     

    Rcat999

     
     
    モノづくりが趣味。 "売っおないなら自分で䜜ればいいじゃない"をコンセプトに、機械/電気/AI/プログラム/ネットワヌク 党郚やりたす。 蚘事執筆はAI䞍䜿甚。 ご連絡や利甚芏玄はプロフィヌル蚘事参照。

    あなたぞのおすすめ