はじめに

ファイルの格納先(ファイルシステム,S3,GCS等)毎にIO処理を記述すると,プログラムが複雑になりがちです.ここでは,それらを統一的に取り扱うことができるsmart_openについて述べます.

やったこと

  • smart_openの導入
  • smart_openによるファイルシステム,クラウドストレージ,Webからのファイル読み込み

smart_openについて

smart_openはビルトインのopenを置き換えることで,様々なプロトコルを用いてファイルをオープンすることを可能にします.現状のプロトコルに対応している様です.

  • S3
  • GCS
  • Blob Storage
  • HDFS
  • ファイルシステム
  • SSH
  • SCP
  • SFTP
  • HTTP

また,以下形式で圧縮されたファイルを透過的に扱うことができます.

  • gzip
  • bzip2

ここでは,ファイルシステム,S3,GCS,HTTPによるファイルアクセスを評価します.

従って,以下のようにクラウドストレージをサポートするsmart_openを導入します.

$ pip install smart_open[all]

他の導入方法については,リポジトリのREADMEを参考にしてください.

クラウドストレージ,Webからファイルを読み込む

通常,クラウドストレージ上のファイルにアクセスするには専用のSDKを使用することが多いと思います. また,HTTPプロトコルでアクセスするには,urllibやrequests等を使用することが多いと思います. そのため,リソースに応じてこれらのライブラリを適切に取り扱う必要があります.

smart_openはこれらのライブラリを適切にラップします.従って,これらのファイルをファイルシステム上にあるかの様に取り扱うことが可能となります.

ここでは,TIFFファイルをGCS, S3, HTTP, ファイルシステム経由で読み込み表示するサンプルを示します.なお,事前に適切な認証情報を設定しておく必要があります.

from smart_open import open
import matplotlib.pyplot as plt
from PIL import Image

sources = {
    "S3": "s3://landsat-pds/L8/003/017/LC80030172015001LGN00/LC80030172015001LGN00_BQA.TIF",
    "HTTP":  "https://s3-us-west-2.amazonaws.com/landsat-pds/L8/003/017/LC80030172015001LGN00/LC80030172015001LGN00_BQA.TIF",
    "FILESYSTEM": "/tmp/LC80030172015001LGN00_BQA.TIF"
}

for protocol, url in sources.items():
    with open(url, "rb") as fp:
        img = Image.open(fp)
        plt.figure()
        plt.title(f"from {protocol}")
        plt.imshow(img, cmap='gray')

pathlib.Path経由でsmart_openを使うことはできるようですが

いかなるリソースもopenで同様に取り扱うことができる事はとても便利です.しかしながら,strでリソースを指定するのは少し大変です.なので,pathlib.Pathでリソースを指定できると便利です.

smart_openはpathlib.Path.openをフックすることできるようです.しかしながら,pathlib.Pathがファイルパスしか扱えない(//が/に置換されてしまう)ので,すこし微妙かもしれません..

from pathlib import Path
Path("https://s3-us-west-2.amazonaws.com/landsat-pds/L8/003/017/LC80030172015001LGN00/LC80030172015001LGN00_BQA.TIF")
PosixPath('https:/s3-us-west-2.amazonaws.com/landsat-pds/L8/003/017/LC80030172015001LGN00/LC80030172015001LGN00_BQA.TIF')

参考