Paepoi

Paepoi » PyGObject Tips » Gio(PyGObject) Tips

Gio(PyGObject) Tips

# 最終更新日 2019.07.20

Python2 関連の削除、点在していた GFile 関連を整理
文字列をシングルクォートに統一、及び fstring 化(python 3.6 以降)を行いました

GFile 基本
#!/usr/bin/env python3

'''
    ファイルの作成、書き込み、コピー、ゴミ箱へ移動
    は GIR ではすべて GFile のメソッドで行います
'''

from gi.repository import Gio

# 以下を都合のいいように変更してください
FILENAME = '新規ファイル.txt'
CONTENTS = '内容\nです'.encode('utf8')
COPYFILE = 'コピー.txt'

# GFile の作成は存在しないファイルでもいい
f = Gio.file_new_for_path(FILENAME)

# 存在しないことの確認
print(f.query_exists())
#=> False

# 新規作成、この関数を呼んだ時点でファイルは作られる
ostream = f.create(Gio.FileCreateFlags.NONE)

# 上書きの場合は replace を使う、実は新規でも使える
# 第二引数を True にすると 新規ファイル.txt~ が自動で作られる
#ostream = f.replace(None, False, Gio.FileCreateFlags.NONE)

# 戻り値の GFileOutputStream を使ってファイル内容を書き込む
# 文字列の場合は UTF-8 に変換するのを忘れずに
ostream.write(CONTENTS)

# 閉じる、この後何もしないならガベージコレクションにまかせてもいい
ostream.close()

# コピー、詳細不要なら以下でいい
c = Gio.file_new_for_path(COPYFILE)
f.copy(c, Gio.FileCopyFlags.NONE)

# ゴミ箱へ移動
f.trash()

# COPYFILE が存在して FILENAME がゴミ箱に入っていることを確認

ファイルの詳細を得る
#!/usr/bin/env python3

'''
    g_file_query_info の引数に得たい情報をコンマ区切りで指定し GFileInfo を得る
    FileInfo オブジェクトのメソッドで情報を出力、という流れで取得できます
    ファイルの種類(Description) は Content Type から変換します
    存在するファイルであれば拡張子は関係無く詳細を取得できる
'''

import sys
from gi.repository import Gio

attr = ','.join([
    Gio.FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
    Gio.FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
    Gio.FILE_ATTRIBUTE_STANDARD_SIZE ])

# このスクリプト自身の詳細を得る
f = Gio.file_new_for_path(__file__)

# g_file_query_info
info = f.query_info(attr, Gio.FileQueryInfoFlags.NONE)

# Content Type を先に得ておく
ct = info.get_content_type()

# 出力
print(f'''----------
Name        : {info.get_display_name()}
Size        : {info.get_size()} byte
Content Type: {ct}
Mime Type   : {Gio.content_type_get_mime_type(ct)}
Description : {Gio.content_type_get_description(ct)}
----------''')

ファイルの詳細を得る(簡易版)
#!/usr/bin/env python3

'''
    ファイルの中身をみないどころか存在すら関係ない版
    Gio.content_type_guess は拡張子依存のようです
    result_uncertain は確実性ですが中身を見ないのでほぼ意味無い
'''

from gi.repository import Gio

# 拡張子から ContentType を得る
ctype = Gio.content_type_guess('a.xml')
print(ctype)
#=> ('application/xml', result_uncertain=False)

# 不明拡張子ならバイナリ扱い、存在しても中身は見ない
b = Gio.content_type_guess('a.homura')
print(b)
#=> ('application/octet-stream', result_uncertain=True)

# 説明を得る
desc = Gio.content_type_get_description ('application/xml')
print(desc)
#=> XML ドキュメント

# サブセットであるか(以下はテキストファイルであるか)
sub = Gio.content_type_is_a('application/xml', 'text/plain')
print(sub)
#=> True

# 実行可能か(+x 属性が付いているかどうかではない)
x = Gio.content_type_can_be_executable('application/x-shellscript')
print(x)
#=> True

# ここから GAppInfo
appinfo = Gio.app_info_get_default_for_type('text/plain', False)

# デフォルトアプリ
defapp = appinfo.get_name() # or executable()
print(defapp)
#=> テキストエディター

非同期読み込み
#!/usr/bin/env python3
 
'''
    同期読み込みでいいなら下記ストリーミング I/O を
    又は f.load_contents にて一気読みしてください
'''

from gi.repository import GLib, Gio

def on_read_file(gfile, res):
    r, contents, etag = gfile.load_contents_finish(res)
    print(contents.decode())
    mainloop.quit()

f = Gio.file_new_for_path(__file__)

# 非同期読み込み開始
f.load_contents_async(None, on_read_file)

# メインループが必要
# GUI で使う場合は Gtk.main() が担当するので必要無い
mainloop = GLib.MainLoop()
mainloop.run()

ストリーミング I/O
#!/usr/bin/env python3

'''
    こちらを使う場合 Python 文字列と UTF-8 は自動変換されます
'''

from gi.repository import Gio

FILENAME = 'suzuki.txt'
TEXT = 'スズキはスクーターも\n\nカッコイイ〜!'

# Write
f = Gio.file_new_for_path(FILENAME)
fstream = f.create(Gio.FileCreateFlags.NONE)
dstream = Gio.DataOutputStream(base_stream=fstream)
dstream.put_string(TEXT)
fstream.close()

# Read
f = Gio.file_new_for_path(FILENAME)
fstream = f.read()
dstream = Gio.DataInputStream(base_stream=fstream)
while True:
    # line に lf は入らない、length はバイト単位
    # line == '' では空文字を判定する、EOF で None になる
    line, length = dstream.read_line_utf8()
    if line == None:
        break
    print(line)
fstream.close()

ディレクトリ内容列挙
#!/usr/bin/env python3

from gi.repository import Gio, GLib

# ディレクトリも GFile
d = Gio.file_new_for_path(GLib.get_home_dir())

# 表示名と隠しファイルかどうかを得る
enum = d.enumerate_children(
    'standard::display-name,standard::is-hidden',
    Gio.FileQueryInfoFlags.NONE)

# info は GFileInfo
for info in enum:
    if not info.get_is_hidden():
        print(info.get_display_name())

ディレクトリを監視
#!/usr/bin/env python3

'''
    ホームディレクトリを監視するサンプル
    GFileMonitor の changed シグナルが変更毎に飛んできます
'''

# mainloop を強制終了させるため
import signal
signal.signal(signal.SIGINT, signal.SIG_DFL)

from gi.repository import Gio, GLib

def on_monitor(monitor, f, other_f, event):
    '''
        隠しファイルの変更も感知します( /.bash.history 等 )
        作成は上書きやリネームでも反応します
    '''
    s = f.get_basename()
    # 隠しファイルは無視、ココを消すと何故かが解る
    if s.startswith('.'): return
    if event == Gio.FileMonitorEvent.CHANGED:
        print(f'{s} の内容が変更されました')
    elif event == Gio.FileMonitorEvent.CHANGES_DONE_HINT:
        print(f'{s} のファイル情報が変更されました')
    elif event == Gio.FileMonitorEvent.DELETED:
        print(f'{s} が削除又は移動されました')
    elif event == Gio.FileMonitorEvent.CREATED:
        print(f'{s} が作成されました')
    elif event == Gio.FileMonitorEvent.ATTRIBUTE_CHANGED:
        print(f'{s} のパーミッションが変更されました')

f = Gio.File.new_for_path(GLib.get_home_dir())
monitor = f.monitor(Gio.FileMonitorFlags.NONE)
monitor.connect('changed', on_monitor)
print('終了するには Ctrl+C を行ってください')
# メインループ
mainloop = GLib.MainLoop()
mainloop.run()

Copyright(C) sasakima-nao All rights reserved 2002 --- 2020.