前の関連記事:LibreOffice5(110)インプットストリームとシークポインタの位置
ドキュメントストレージから取得したストリームをPythonのバイナリーストリームでファイルに書き込む
LibreOffice5(108)ドキュメントストレージからファイルシステムストレージにデータをコピーすると同様に一つ上の階層にあるodsファイルを一つ取得して、そのファイル内のマクロフォルダを、取得したodsファイルと同じ階層のsrcフォルダ内に書き出します。
#!/opt/libreoffice5.4/program/python # -*- coding: utf-8 -*- import unohelper # オートメーションには必須(必須なのはuno)。 import glob import os import shutil from com.sun.star.embed import ElementModes # 定数 def macro(): # マクロで実行は不可。 ctx = XSCRIPTCONTEXT.getComponentContext() # コンポーネントコンテクストの取得。 smgr = ctx.getServiceManager() # サービスマネージャーの取得。 os.chdir("..") # 一つ上のディレクトリに移動。 ods = glob.glob("*.ods")[0] # odsファイルを取得。最初の一つのみ取得。 systempath = os.path.join(os.getcwd(), ods) # odsファイルのフルパス。 doc_fileurl = unohelper.systemPathToFileUrl(systempath) # fileurlに変換。 desktop = ctx.getByName('/singletons/com.sun.star.frame.theDesktop') # デスクトップの取得。 components = desktop.getComponents() # ロードしているコンポーネントコレクションを取得。 for component in components: # 各コンポーネントについて。 if hasattr(component, "getURL"): # スタートモジュールではgetURL()はないため。 if component.getURL()==doc_fileurl: # fileurlが一致するとき documentstorage = component.getDocumentStorage() # コンポーネントからストレージを取得。 break else: # ドキュメントが開いていない時。 storagefactory = smgr.createInstanceWithContext('com.sun.star.embed.StorageFactory', ctx) # StorageFactory documentstorage = storagefactory.createInstanceWithArguments((doc_fileurl, ElementModes.READ)) # odsファイルからストレージを読み取り専用で取得。 if not ("Scripts" in documentstorage and "python" in documentstorage["Scripts"]): # ドキュメント内に埋め込みマクロフォルダがない時は終了する。 print("The embedded macro folder does not exist in {}.".format(ods)) return dest_path = os.path.join(os.getcwd(), "src", "Scripts", "python") # 出力先フォルダのパスを取得。 if os.path.exists(dest_path): # 出力先フォルダが存在すれば削除する。 shutil.rmtree(dest_path) os.makedirs(dest_path) # 出力先フォルダを作成。 scriptsstorage = documentstorage["Scripts"] # documentstorage["Scripts"]["python"]ではイテレーターになれない。 getContents(scriptsstorage["python"], dest_path) # 再帰的にストレージの内容を出力先フォルダに展開。 def getContents(storage, dest): # ストレージ、出力先フォルダ for name in storage: # ストレージの各要素名について。 if storage.isStorageElement(name): # ストレージの時。 subdest = os.path.join(dest, name) # 出力先フォルダのパスを取得。 if not os.path.exists(subdest): # 出力先フォルダが存在しなければ作成する。 os.mkdir(subdest) getContents(storage[name], subdest) # 子要素について同様にする。 elif storage.isStreamElement(name): # ストリームの時。 inputstream = storage[name].getInputStream() # 読み取るファイルのインプットストリームを取得。 dummy, b = inputstream.readBytes([], inputstream.available()) # パッシブデータソースからバイトシークエンスを取得。 inputstream.closeInput() # 必要?インプットストリームを閉じる。 filepath = os.path.join(dest, name) # 書き込み先ファイルのパスの取得。 with open(filepath, "wb") as f: # 書き込み先ファイルの作成。 f.write(bytes(b)) # バイト列をファイルに書き込む。 if __name__ == "__main__": # オートメーションで実行するとき def automation(): # オートメーションのためにglobalに出すのはこの関数のみにする。 import officehelper from functools import wraps import sys from com.sun.star.beans import PropertyValue # Struct from com.sun.star.script.provider import XScriptContext def connectOffice(func): # funcの前後でOffice接続の処理 @wraps(func) def wrapper(): # LibreOfficeをバックグラウンドで起動してコンポーネントテクストとサービスマネジャーを取得する。 try: ctx = officehelper.bootstrap() # コンポーネントコンテクストの取得。 except: print("Could not establish a connection with a running office.", file=sys.stderr) sys.exit() print("Connected to a running office ...") smgr = ctx.getServiceManager() # サービスマネジャーの取得。 print("Using {} {}".format(*_getLOVersion(ctx, smgr))) # LibreOfficeのバージョンを出力。 return func(ctx, smgr) # 引数の関数の実行。 def _getLOVersion(ctx, smgr): # LibreOfficeの名前とバージョンを返す。 cp = smgr.createInstanceWithContext('com.sun.star.configuration.ConfigurationProvider', ctx) node = PropertyValue(Name = 'nodepath', Value = 'org.openoffice.Setup/Product' ) # share/registry/main.xcd内のノードパス。 ca = cp.createInstanceWithArguments('com.sun.star.configuration.ConfigurationAccess', (node,)) return ca.getPropertyValues(('ooName', 'ooSetupVersion')) # LibreOfficeの名前とバージョンをタプルで返す。 return wrapper @connectOffice # createXSCRIPTCONTEXTの引数にctxとsmgrを渡すデコレータ。 def createXSCRIPTCONTEXT(ctx, smgr): # XSCRIPTCONTEXTを生成。 class ScriptContext(unohelper.Base, XScriptContext): def __init__(self, ctx): self.ctx = ctx def getComponentContext(self): return self.ctx def getDesktop(self): return ctx.getByName('/singletons/com.sun.star.frame.theDesktop') # com.sun.star.frame.Desktopはdeprecatedになっている。 def getDocument(self): return self.getDesktop().getCurrentComponent() return ScriptContext(ctx) return createXSCRIPTCONTEXT() # XSCRIPTCONTEXTの取得。 XSCRIPTCONTEXT = automation() # XSCRIPTCONTEXTを取得。 macro()ファイルシステムストレージよりもPythonのバイナリーストリームの方が16.2. io — ストリームを扱うコアツール — Python 3.5.3 ドキュメントに詳しく解説があるので扱いやすいです。
47行目でwrite()メソッドでバイト列を書き込んでいます。
フォルダもPythoのメソッドで作成しています。
write()メソッドの引数はbytes-like objectなので、bytesクラスに変換して渡しています。
bytearrayクラスに変換しても動きましたが、readBytes()の戻り値のsequence<byte>(バイトのタプル)をそのまま渡すとTypeErrorがでてきました。
参考にしたサイト
16.2. io — ストリームを扱うコアツール — Python 3.5.3 ドキュメント
Pythonでのストリームの解説。
0 件のコメント:
コメントを投稿