L'Isola di Niente
L'Isola di Niente » PyGObject Tips » Gio(PyGObject) Tips

Gio Tips

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

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

import sys
from gi.repository import Gio

res = """----------
Name        : {0}
Size        : {1} byte
Content Type: {2}
Mime Type   : {3}
Description : {4}
----------"""

attr = (
    Gio.FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
    Gio.FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
    Gio.FILE_ATTRIBUTE_STANDARD_SIZE )

# Create GLocalFile
f = Gio.file_new_for_path(__file__)
# Create GFileInfo
info = f.query_info(
    ",".join(attr),
    Gio.FileQueryInfoFlags.NONE,
    None )
# Get Content Type
ct = info.get_content_type()
# echo
output = res.format(
    info.get_display_name(),
    info.get_size(),
    ct,
    Gio.content_type_get_mime_type(ct),
    Gio.content_type_get_description(ct) )
print(output)

"""
----------
Name        : test.py
Size        : 897 byte
Content Type: text/x-python
Mime Type   : text/x-python
Description : Python スクリプト
----------
"""

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

"""
    ファイルの存在は関係ない版、ということで
    Gio.content_type_guess は拡張子依存のようです
"""

from gi.repository import Gio

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

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

# 説明を得る
desc = Gio.content_type_get_description (ctype[0])
print(desc)
#=> XML ドキュメント

# サブセットであるか(以下はテキストファイルであるか)
sub = Gio.content_type_is_a(ctype[0], "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)
#=> gedit

# そのディスプレイネーム
dispname = appinfo.get_display_name()
print(dispname)
#=> gedit テキストエディター

フルパス、URI 相互変換
#!/usr/bin/env python3

"""
    urllib でも GLib でも変換できるけど
    GFile を使う場合はそのまま値を得ることができる
    半角空白や日本語部分もしっかり相互変換される
"""

from gi.repository import Gio

s = "/path/to/on spaceあ.txt"

f = Gio.file_new_for_path(s)
uri = f.get_uri()
print(uri) #=> file:///path/to/on%20space%E3%81%82.txt

f = Gio.file_new_for_uri(uri)
path = f.get_path()
print(path) #=> /path/to/on spaceあ.txt

ファイルの存在確認、コピー、移動
#!/usr/bin/env python3

"""
    GFile を作成し query_exists, copy, move
    ハンドラは None でもいい
"""

from gi.repository import Gio

def on_copy(current, total, data):
    print("total {0} byte {1}".format(total, data))

f = Gio.file_new_for_path("first.txt")
if f.query_exists(None):
    # Copy
    c = Gio.file_new_for_path("copy.txt")
    f.copy(c, Gio.FileCopyFlags.NONE, None, on_copy, "Copy")
    # Move
    m = Gio.file_new_for_path("move.txt")
    f.move(m, Gio.FileCopyFlags.NONE, None, on_copy, "Move")

ファイルをゴミ箱に捨てる
#!/usr/bin/env python3

# GFile を作成し trash メソッドを呼ぶだけ

import sys
from gi.repository import Gio

if len(sys.argv) > 1:
    f = Gio.file_new_for_path(sys.argv[1])
    f.trash(None)

メモリにバイナリを読み込む
#!/usr/bin/env python3

"""
    g_load_contents で読み込むとバイナリになる
    PyGObject 3.14 以前で使う場合は f.load_contents(None)
"""

from gi.repository import Gio, GLib

fn = __file__
# Create GLocalFile
f = Gio.File.new_for_path(fn)
# load_contents
result, contents, length = f.load_contents()
if result:
    # テキスト文書なら decode すれば文字列になる
    # Python2 であればそのまま文字列ですので注意
    print(contents.decode("utf-8"))

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

"""
    PyGObject 3.14 以前で使う場合は
    GCancellable 指定部分を全部 None で埋めてください
"""

from gi.repository import Gio

filename = "output.txt"
lines = """QB
鹿目まどか
暁美ほむら

巴マミ"""

# Write
f = Gio.file_new_for_path(filename)
fstream = f.replace("", False, Gio.FileCreateFlags.NONE)
dstream = Gio.DataOutputStream.new(fstream)
dstream.put_string(lines)
fstream.close()

# Read
f = Gio.file_new_for_path(filename)
fstream = f.read()
dstream = Gio.DataInputStream.new(fstream)
while 1:
    text, length = dstream.read_line_utf8()
    if text == None:
        break
    # length はバイト単位
    print("{0}({1})".format(text, length))
fstream.close()

""" outtput
QB(2)
鹿目まどか(15)
暁美ほむら(15)
(0)
巴マミ(9)
"""

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

import os
from gi.repository import Gio, GLib

# ディレクトリも GFile
d = Gio.file_new_for_path(GLib.get_home_dir());
# Get GFileEnumerator
enum = d.enumerate_children(
        Gio.FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
        Gio.FileQueryInfoFlags.NONE,
        None )
for info in enum:
    # info is GFileInfo
    print(info.get_display_name())

ファイル、ディレクトリを監視
#!/usr/bin/env python3

"""
    $HOME を監視するサンプル、mainloop が必要なので GUI で
    GFileMonitor の changed シグナルが変更毎に飛んできます
"""

from gi.repository import Gtk, Gio, GLib

class Win(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self)
        self.view = Gtk.TextView()
        self.view.set_editable(False)
        sw = Gtk.ScrolledWindow()
        sw.add(self.view)
        self.add(sw)
        #
        # ファイル監視も同様、現在存在していない場合でも監視してくれる
        #f = Gio.File.new_for_path(GLib.get_home_dir() + "/test.txt")
        f = Gio.File.new_for_path(GLib.get_home_dir())
        #
        # GFileMonitor は他メソッドで使わなくても必ずアトリビュートにする
        # しないと __init__ 抜けた時点で破棄されてしまう
        #
        self.monitor = f.monitor(Gio.FileMonitorFlags.NONE)
        #self.monitor = f.monitor(Gio.FileMonitorFlags.SEND_MOVED)
        self.monitor.connect("changed", self.on_monitor)
        # self
        self.connect("delete-event", Gtk.main_quit)
        self.resize(300, 200)
        self.show_all()

    def on_monitor(self, monitor, f, other_f, event):
        """
            ディレクトリ監視は隠しファイルの変更も感知します
            ( /.bash.history 等 )
        """
        buf = self.view.get_buffer()
        s = f.get_path()
        if event == Gio.FileMonitorEvent.CHANGED:
            # ファイルの内容が変更された時
            buf.insert_at_cursor("CHANGED: {0}\n".format(s))
        elif event == Gio.FileMonitorEvent.CHANGES_DONE_HINT:
            # ファイルの情報が変更された時
            buf.insert_at_cursor("CHANGES_DONE_HINT: {0}\n".format(s))
        elif event == Gio.FileMonitorEvent.DELETED:
            # 削除(リネーム、移動含む)された時
            buf.insert_at_cursor("DERETED: {0}\n".format(s))
        elif event == Gio.FileMonitorEvent.CREATED:
            # 作成(リネーム、移動含む)された時
            buf.insert_at_cursor("CREATED: {0}\n".format(s))
        elif event == Gio.FileMonitorEvent.ATTRIBUTE_CHANGED:
            # パーミッションが変わった時
            buf.insert_at_cursor("ATTRIBUTE_CHANGED: {0}\n".format(s))
        elif event == Gio.FileMonitorEvent.PRE_UNMOUNT:
            # Gio.FileMonitorFlags.WATCH_MOUNTS 指定時のみ
            buf.insert_at_cursor("PRE_UNMOUNT: {0}\n".format(s))
        elif event == Gio.FileMonitorEvent.UNMOUNTED:
            # Gio.FileMonitorFlags.WATCH_MOUNTS 指定時のみ
            buf.insert_at_cursor("UNMOUNTED: {0}\n".format(s))
        elif event == Gio.FileMonitorEvent.MOVED:
            # Gio.FileMonitorFlags.SEND_MOVED 指定時のみ
            buf.insert_at_cursor("MOVED: {0}\n".format(s))
        # Gio.FileMonitorFlags.SEND_MOVED 指定時に
        if other_f:
            buf.insert_at_cursor("other: {0}\n".format(f.get_path()))

Win()
Gtk.main()
Copyright(C) sasakima-nao All rights reserved 2002 --- 2017.