输入/输出和文件系统#

Arrow 提供了一系列 C++ 接口,抽象了输入/输出操作的具体细节。它们操作无类型二进制数据流。这些抽象用于各种目的,例如读取 CSV 或 Parquet 数据、传输 IPC 流等。

读取二进制数据#

用于读取二进制数据的接口有两种形式

  • 顺序读取:InputStream 接口提供 Read 方法;建议 ReadBuffer,因为在某些情况下可以避免内存复制。

  • 随机访问读取:RandomAccessFile 接口提供额外的定位功能,最重要的是 ReadAt 方法,它允许从多个线程进行并行读取。

可用于内存读取无缓冲文件读取内存映射文件读取缓冲读取压缩读取的具体实现。

写入二进制数据#

二进制数据的写入主要通过 OutputStream 接口完成。

可用于内存写入无缓冲文件写入内存映射文件写入缓冲写入压缩写入的具体实现。

文件系统#

文件系统接口 允许抽象访问各种数据存储后端,例如本地文件系统或 S3 存储桶。它提供输入和输出流以及目录操作。

另请参阅

文件系统 API 参考.

文件系统接口公开了底层数据存储的简化视图。数据路径表示为抽象路径,它们以 / 分隔,即使在 Windows 上也是如此,并且不应包含特殊的路径组件,例如 ...。如果底层存储支持,符号链接会自动解引用。只提供文件条目的基本 元数据,例如文件大小和修改时间。

文件系统实例可以使用 FromUri 工厂函数从 URI 字符串构造,这些工厂函数根据 URI 的 scheme 分派给特定于实现的工厂。新实例的其他属性从 URI 的其他属性中提取,例如 hostnameusername 等。Arrow 支持新文件系统的运行时注册,并为多个文件系统提供内置支持。

支持哪些内置文件系统是在构建时配置的,可能包括本地文件系统访问HDFS与 Amazon S3 兼容的存储Google Cloud Storage

注意

使用文件系统的任务通常会在 I/O 线程池上运行。对于支持高并发性的文件系统,增加 I/O 线程池的大小可能会带来好处。

定义新文件系统#

可以通过使用 RegisterFileSystemFactory() 为每个新的 URI 方案注册一个工厂,从而向 FromUri 工厂函数添加对其他 URI 方案的支持。为了实现常见情况,即更喜欢自动注册,可以在命名空间范围内定义一个 FileSystemRegistrar 实例,该实例将在实例加载时注册一个工厂。

auto kExampleFileSystemModule = ARROW_REGISTER_FILESYSTEM(
  "example",
  [](const Uri& uri, const io::IOContext& io_context,
      std::string* out_path) -> Result<std::shared_ptr<arrow::fs::FileSystem>> {
    EnsureExampleFileSystemInitialized();
    return std::make_shared<ExampleFileSystem>();
  },
  &EnsureExampleFileSystemFinalized
);

如果文件系统实现需要在使用任何实例之前进行初始化,则应将其包含在相应的工厂中,或以其他方式确保在调用工厂之前自动完成。同样,如果文件系统实现需要在进程结束之前进行拆卸,则可以将其封装在一个函数中并与工厂一起注册。所有终结器都将由 EnsureFinalized() 调用。

通过将文件系统实现划分到单独的共享库中,可以降低构建复杂性,应用程序可以动态链接或加载该库。Arrow 的内置文件系统实现也遵循此模式。如果包含 FileSystemRegistrar 实例的共享库必须动态加载,则应使用 LoadFileSystemFactories() 加载它。如果此类库可能静态链接到 arrow,则它应该有一个源文件 #include "arrow/filesystem/filesystem_library.h",以确保存在 LoadFileSystemFactories() 依赖的符号。