LibreOffice5(110)インプットストリームとシークポインタの位置

2017-12-16

旧ブログ

t f B! P L
単純にファイルシステムストレージからインプットストリームを取得するだけでは、データが読み取れませんでした。解決法はわかりましたが、インプットストリームとシークポインタの関係は理解できない点が残りました。

前の関連記事:LibreOffice5(109)子要素にフォルダしか持たないドキュメント内フォルダ


インプットストリームから取得できるバイト数が0になっている


LibreOffice5(103)ファイルシステムストレージのサービスとインターフェイスの一覧

これをみるとファイルシステムストレージからインプットストリームを取得できるのは、XStorageインターフェイスのcloneStreamElement()メソッドかopenStreamElement()メソッドかXNameAccessインターフェイスのgetByName()メソッドになります。
 filesystemstoragefactory = smgr.createInstanceWithContext('com.sun.star.embed.FileSystemStorageFactory', ctx)
 filesystemstorage = filesystemstoragefactory.createInstanceWithArguments((sourcedir, ElementModes.READ))  # ファイルシステムストレージを取得。
 for name in filesystemstorage:
  if filesystemstorage.isStreamElement(name):
   xstream = filesystemstorage.cloneStreamElement(name)
   inputstream = xstream.getInputStream()
   print(inputstream.available())  # 0
   xstream = filesystemstorage.openStreamElement(name, ElementModes.READ)
   inputstream = xstream.getInputStream()
   print(inputstream.available())  # 0
   xstream = filesystemstorage[name]
   inputstream = xstream.getInputStream()
   print(inputstream.available())  # 0  
sourcedirはpyファイルが入ったフォルダへのfileurlです。

ElementModesは定数です。

データの入っているファイルに対しても、これを実行するといずれもavailable()では0が返ってきてしまいます。

XHierarchicalStorageAccessインターフェイスのメソッドでもインプットストリームを取得できそうでしたが、openStreamElementByHierarchicalName()メソッドに渡すストリームのパスの方法がわかりませんでした。

XStorageインターフェイスのcloneStreamElement()メソッドの戻り値のインプットストリームからデータを取得可能


XStorageインターフェイスのopenStreamElement()メソッドとXNameAccessインターフェイスのgetByName()メソッドはXStreamインターフェイスしか実装していないオブジェクトが返ってこないのに対して、XStorageインターフェイスcloneStreamElement()メソッドでは一時ファイルが返ってくることがわかりました。

一時ファイルはXSeekableインターフェイスをもっています。
 filesystemstoragefactory = smgr.createInstanceWithContext('com.sun.star.embed.FileSystemStorageFactory', ctx)
 filesystemstorage = filesystemstoragefactory.createInstanceWithArguments((sourcedir, ElementModes.READ))  # ファイルシステムストレージを取得。
 for name in filesystemstorage:
  if filesystemstorage.isStreamElement(name):
   xstream = filesystemstorage.cloneStreamElement(name)
   inputstream = xstream.getInputStream()
   print(inputstream.available())  # 0
   print(inputstream.getLength())  # 263
   print(inputstream.getPosition())  # 263
getLength()メソッドでインプットストリームの長さがわかります。

getPosition()メソッドでシークポインタの位置が取得できます。

今回の場合はいずれも263が返ってきているのに、available()メソッドでは0なので、0バイトしか読み込めていないのがわかります。

これをseek()メソッドでシークポインタをストリームの先端に移動させます。
   inputstream.seek(0)  # シークポインタをストリームの先頭に移動させる。
   print(inputstream.getPosition())  # 0
   print(inputstream.available())  # 263
これでストリームの先頭から全部取得できました。

しかし一時ファイルを利用するこの方法はディスクにあるファイルをまたディスクにコピーする無駄が生じるので、SimpleFileAccessのopenFileRead()メソッドでインプットストリームを取得する方法を思いつきましたが、結局それはうまくいきませんでした。

SimpleFileAccessのopenFileRead()メソッドの戻り値のインプットストリーム


fileurlを取得できるのならSimpleFileAccessのopenFileRead()メソッドでインプットストリームが取得できます。
def macro():
 ctx = XSCRIPTCONTEXT.getComponentContext()  # コンポーネントコンテクストの取得。
 smgr = ctx.getServiceManager()  # サービスマネージャーの取得。 
 tcu = smgr.createInstanceWithContext("pq.Tcu", ctx)  # サービス名か実装名でインスタンス化。
 simplefileaccess = smgr.createInstanceWithContext("com.sun.star.ucb.SimpleFileAccess", ctx)  # SimpleFileAccess
 doc = XSCRIPTCONTEXT.getDocument()  # ドキュメント。
 inputstream = simplefileaccess.openFileRead(doc.getURL())
 tcu.wtree(inputstream)
このopenFileRead()メソッドの戻り値のサービスとインターフェイスの一覧を取得してみました。

doc.getURL()はディスク上に保存したドキュメントのときしか戻り値が返ってこないので、保存していないドキュメントに対して実行すると7行目でInteractiveAugmentedIOExceptionになります。


├─.io.XInputStream
│      long  available()
│      void  closeInput()
│      long  readBytes( [out] [byte] aData,
│                       [in]   long nBytesToRead
│            ) raises ( .io.IOException,
│                       .io.BufferSizeExceededException,
│                       .io.NotConnectedException)
│      long  readSomeBytes( [out] [byte] aData,
│                           [in]   long nMaxBytesToRead
│                ) raises ( .io.IOException,
│                           .io.BufferSizeExceededException,
│                           .io.NotConnectedException)
│      void  skipBytes( [in] long nBytesToSkip
│            ) raises ( .io.IOException,
│                       .io.BufferSizeExceededException,
│                       .io.NotConnectedException)
└─.io.XSeekable
        hyper  getLength()
        hyper  getPosition()
         void  seek( [in] hyper location
          ) raises ( .io.IOException,
                     .lang.IllegalArgumentException)

XSeekableインターフェイスをもっているのでインプットストリームの長さとシークポインタの位置を確認できます。
   inputstream = simplefileaccess.openFileRead("/".join((sourcedir, name))) 
   print(inputstream.getLength())  # 263
   print(inputstream.getPosition())  # 0
   print(inputstream.available())  # 0 
sourcedirはフォルダへのfileurl、nameはpyファイル名です。

これは想定外の結果になりました。

ストリームの長さが263バイトで、シークポインタの位置が0バイト目なのに読み込めるバイト数が0になっていて理解できません。

openFileReadWrite()メソッドで取得したインプットストリームでも同じ結果でした。

SimpleFileAccessのopenFileReadWrite()とopenFileWrite()の戻り値のサービスとインターフェイスの一覧

def macro():
 ctx = XSCRIPTCONTEXT.getComponentContext()  # コンポーネントコンテクストの取得。
 smgr = ctx.getServiceManager()  # サービスマネージャーの取得。 
 tcu = smgr.createInstanceWithContext("pq.Tcu", ctx)  # サービス名か実装名でインスタンス化。
 simplefileaccess = smgr.createInstanceWithContext("com.sun.star.ucb.SimpleFileAccess", ctx)  # SimpleFileAccess
 doc = XSCRIPTCONTEXT.getDocument()  # ドキュメント。
 xstream = simplefileaccess.openFileWrite(doc.getURL())
 tcu.wtree(xstream)
SimpleFileAccessのopenFileReadWrite()とopenFileWrite()の戻り値のサービスとインターフェイスは同一でした。

object
├─.io.XAsyncOutputMonitor
│      void  waitForCompletion()
├─.io.XInputStream
│      long  available()
│      void  closeInput()
│      long  readBytes( [out] [byte] aData,
│                       [in]   long nBytesToRead
│            ) raises ( .io.IOException,
│                       .io.BufferSizeExceededException,
│                       .io.NotConnectedException)
│      long  readSomeBytes( [out] [byte] aData,
│                           [in]   long nMaxBytesToRead
│                ) raises ( .io.IOException,
│                           .io.BufferSizeExceededException,
│                           .io.NotConnectedException)
│      void  skipBytes( [in] long nBytesToSkip
│            ) raises ( .io.IOException,
│                       .io.BufferSizeExceededException,
│                       .io.NotConnectedException)
├─.io.XOutputStream
│      void  closeOutput()
│      void  flush()
│      void  writeBytes( [in] [byte] aData
│             ) raises ( .io.IOException,
│                        .io.BufferSizeExceededException,
│                        .io.NotConnectedException)
├─.io.XSeekable
│      hyper  getLength()
│      hyper  getPosition()
│       void  seek( [in] hyper location
│        ) raises ( .io.IOException,
│                   .lang.IllegalArgumentException)
├─.io.XStream
│       .io.XInputStream  getInputStream()
│      .io.XOutputStream  getOutputStream()
└─.io.XTruncate
        void  truncate()


次の関連記事:LibreOffice5(111)インプットストリームのバイトシークエンスをファイルに書き込む

ブログ検索 by Blogger

Translate

最近のコメント

Created by Calendar Gadget

QooQ