文件系统接口#

PyArrow 附带了抽象的文件系统接口,以及针对各种存储类型的具体实现。

文件系统接口提供输入和输出流以及目录操作。它暴露了底层数据存储的简化视图。数据路径被表示为抽象路径,即使在 Windows 上,也是用 / 分隔的,不应该包含特殊路径组件,如 ... 如果底层存储支持符号链接,它们会被自动解引用。只有关于文件条目的基本元数据,如文件大小和修改时间,是可用的。

用法#

实例化文件系统#

可以使用构造函数创建 FileSystem 对象(并检查相应的构造函数以了解其选项):

from pyarrow import fs
local = fs.LocalFileSystem()

或者可以从 URI 推断出来:

s3, path = fs.FileSystem.from_uri("s3://my-bucket")
s3
<pyarrow._s3fs.S3FileSystem at 0x7f2a0c2e82f0>
path
'my-bucket'

读取和写入文件#

PyArrow 中的许多与 IO 相关的函数接受 URI(并推断出文件系统)或明确的文件系统参数来指定要读取或写入的文件系统。例如, pyarrow.parquet.read_table() 函数可以以以下方式使用:

import pyarrow.parquet as pq

# using a URI -> filesystem is inferred
pq.read_table("s3://my-bucket/data.parquet")
# using a path and filesystem
s3 = fs.S3FileSystem("..")
pq.read_table("my-bucket/data.parquet", filesystem=s3)

文件系统接口进一步允许直接打开文件进行读取(输入)或写入(输出),这可以与使用类似文件的对象的函数结合使用。例如:

import pyarrow as pa

local = fs.LocalFileSystem()

with local.open_output_stream("test.arrow") as file:
   with pa.RecordBatchFileWriter(file, table.schema) as writer:
      writer.write_table(table)

列出文件#

可以使用 pyarrow.fs.~FileSystem.get_file_info() 方法检查文件系统上的目录和文件。要列出目录的内容,请使用 FileSelector 对象指定选择:

>>> local.get_file_info(fs.FileSelector("dataset/", recursive=True))
[<FileInfo for 'dataset/part=B': type=FileType.Directory>,
 <FileInfo for 'dataset/part=B/data0.parquet': type=FileType.File, size=1564>,
 <FileInfo for 'dataset/part=A': type=FileType.Directory>,
 <FileInfo for 'dataset/part=A/data0.parquet': type=FileType.File, size=1564>]

这将返回 FileInfo 对象列表,其中包含有关类型(文件或目录)、大小、最后修改日期等信息。

您也可以为单个明确路径(或路径列表)获取这些信息:

>>> local.get_file_info('test.arrow')
<FileInfo for 'test.arrow': type=FileType.File, size=3250>

>>> local.get_file_info('non_existent')
<FileInfo for 'non_existent': type=FileType.NotFound>

本地文件系统#

LocalFileSystem 允许您访问本地计算机上的文件。

如何将数据写入磁盘并读取回来的示例:

>>> from pyarrow import fs
>>> local = fs.LocalFileSystem()
>>> with local.open_output_stream('/tmp/pyarrowtest.dat') as stream:
        stream.write(b'data')
4
>>> with local.open_input_stream('/tmp/pyarrowtest.dat') as stream:
        print(stream.readall())
b'data'

S3#

PyArrow 原生实现了适用于 S3 兼容存储的 S3 文件系统。

S3FileSystem 构造函数有几个选项来配置 S3 连接(例如,凭证、区域、端点覆盖等)。此外,构造函数还将检查 AWS 支持的配置的S3凭证(如 AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY 环境变量、AWS 配置文件,以及 EC2 节点的 EC2 实例元数据服务)。

如何从 S3 存储桶读取内容的示例:

>>> from pyarrow import fs
>>> s3 = fs.S3FileSystem(region='eu-west-3')

>>> # List all contents in a bucket, recursively
>>> s3.get_file_info(fs.FileSelector('my-test-bucket', recursive=True))
[<FileInfo for 'my-test-bucket/File1': type=FileType.File, size=10>,
 <FileInfo for 'my-test-bucket/File5': type=FileType.File, size=10>,
 <FileInfo for 'my-test-bucket/Dir1': type=FileType.Directory>,
 <FileInfo for 'my-test-bucket/Dir2': type=FileType.Directory>,
 <FileInfo for 'my-test-bucket/EmptyDir': type=FileType.Directory>,
 <FileInfo for 'my-test-bucket/Dir1/File2': type=FileType.File, size=11>,
 <FileInfo for 'my-test-bucket/Dir1/Subdir': type=FileType.Directory>,
 <FileInfo for 'my-test-bucket/Dir2/Subdir': type=FileType.Directory>,
 <FileInfo for 'my-test-bucket/Dir2/Subdir/File3': type=FileType.File, size=10>]

>>> # Open a file for reading and download its contents
>>> f = s3.open_input_stream('my-test-bucket/Dir1/File2')
>>> f.readall()
b'some data'

请注意,为正在使用的存储桶配置 S3FileSystem 时,正确设置区域非常重要。如果未设置区域,AWS SDK 将选择一个值,如果 SDK 版本 <1.8,默认为 'us-east-1'。否则,它将尝试使用各种启发式方法(环境变量、配置文件、EC2 元数据服务器)来解析区域。

也可以通过使用 pyarrow.fs.resolve_s3_region()pyarrow.fs.S3FileSystem.from_uri() 从存储桶名称解析 S3FileSystem 的区域。

以下是一些代码示例:

from pyarrow import fs
s3 = fs.S3FileSystem(region=fs.resolve_s3_region('my-test-bucket'))
# Or via URI:
s3, path = fs.S3FileSystem.from_uri('s3://[access_key:secret_key@]bucket/path]')

小技巧

在使用 S3FileSystem 时,只有出现致命错误或打印返回值时才会产生输出。为了排除故障,可以使用环境变量ARROW_S3_LOG_LEVEL设置日志级别。在运行任何与S3交互的代码之前,必须设置日志级别。可能的值包括FATAL(默认)、ERROR、WARN、INFO、DEBUG(推荐)、TRACE和OFF。

谷歌云存储文件系统#

PyArrow 为 GCS 存储本地实现了 Google Cloud Storage (GCS) 支持的文件系统。

如果不在 Google Cloud Platform (GCP) 上运行,则通常需要环境变量 GOOGLE_APPLICATION_CREDENTIALS 指向包含凭据的 JSON 文件。或者,使用 gcloud CLI 在默认位置生成凭据文件:

gcloud auth application-default login

要连接到一个公共存储桶而不使用任何凭证,你必须在 GcsFileSystem 中传入 anonymous=True。否则,文件系统会报告无法解析主机名,因为经过身份验证和公共访问的主机名不同。

示例展示了如何从 GCS 存储桶中读取内容:

>>> from datetime import timedelta
>>> from pyarrow import fs
>>> gcs = fs.GcsFileSystem(anonymous=True, retry_time_limit=timedelta(seconds=15))

>>> # List all contents in a bucket, recursively
>>> uri = "gcp-public-data-landsat/LC08/01/001/003/"
>>> file_list = gcs.get_file_info(fs.FileSelector(uri, recursive=True))

>>> # Open a file for reading and download its contents
>>> f = gcs.open_input_stream(file_list[0].path)
>>> f.read(64)
b'GROUP = FILE_HEADER\n  LANDSAT_SCENE_ID = "LC80010032013082LGN03"\n  S'

使用 Arrow 支持的 fsspec 兼容文件系统#

上述提到的文件系统都是 Arrow C++/PyArrow 原生支持的。然而,Python 生态系统中也有几个文件系统包。遵循 fsspec 接口的这些包也可以在 PyArrow 中使用。

接受文件系统对象的函数也将接受 fsspec 子类。例如:

# creating an fsspec-based filesystem object for Google Cloud Storage
import gcsfs
fs = gcsfs.GCSFileSystem(project='my-google-project')

# using this to read a partitioned dataset
import pyarrow.dataset as ds
ds.dataset("data/", filesystem=fs)

Azure Blob Storage 也类似:

import adlfs
# ... load your credentials and configure the filesystem
fs = adlfs.AzureBlobFileSystem(account_name=account_name, account_key=account_key)

import pyarrow.dataset as ds
ds.dataset("mycontainer/data/", filesystem=fs)

在底层,fsspec 文件系统对象被包装成基于 Python 的 PyArrow 文件系统(PyFileSystem),使用 FSSpecHandler。你也可以手动执行此操作,以获取具有 PyArrow 文件系统接口的对象:

from pyarrow.fs import PyFileSystem, FSSpecHandler
pa_fs = PyFileSystem(FSSpecHandler(fs))

然后,你可以访问 FileSystem 的所有功能:

# write data
with pa_fs.open_output_stream('mycontainer/pyarrowtest.dat') as stream:
   stream.write(b'data')

# read data
with pa_fs.open_input_stream('mycontainer/pyarrowtest.dat') as stream:
   print(stream.readall())
#b'data'

# read a partitioned dataset
ds.dataset("data/", filesystem=pa_fs)

使用 Arrow 文件系统与 fsspec#

Arrow 文件系统接口具有有限的、面向开发者的 API 接口。这对于基本交互和使用 Arrow 的 IO 功能是足够的。另一方面,fsspec 接口提供了一个非常大的API,包含许多辅助方法。如果你想使用这些方法,或者你需要与期望使用fsspec兼容的文件系统对象的软件包进行交互,你可以使用fsspec来包装一个Arrow文件系统对象。

从 2021.09 版本的 fsspec 开始,可以使用 ArrowFSWrapper 来实现这一点:

from pyarrow import fs
local = fs.LocalFileSystem()
from fsspec.implementations.arrow import ArrowFSWrapper
local_fsspec = ArrowFSWrapper(local)

生成的对象现在具有 fsspec 兼容的接口,同时在底层由 Arrow 文件系统支持。以下是一个创建目录和文件、列出内容的示例用法:

local_fsspec.mkdir("./test")
local_fsspec.touch("./test/file.txt")
local_fsspec.ls("./test/")
['./test/file.txt']

要了解更多信息,请参阅 fsspec 文档