You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用C++ Apache Arrow库读取Snappy压缩的Parquet文件?

问题描述

我用以下C++代码可以正常读取未压缩的b.parquet文件:

#include <iostream>
#include <arrow/api.h>
#include <arrow/io/api.h>
#include <arrow/ipc/reader.h>
#include <arrow/util/logging.h>
#include <arrow/ipc/api.h>
#include <parquet/arrow/reader.h>
#include <parquet/arrow/writer.h>


arrow::Status RunMain() {

    auto pool = arrow::default_memory_pool();

    std::shared_ptr<arrow::io::ReadableFile> file;
    ARROW_ASSIGN_OR_RAISE(file, arrow::io::ReadableFile::Open("b.parquet"));

    std::unique_ptr<parquet::arrow::FileReader> reader;
    PARQUET_THROW_NOT_OK(parquet::arrow::OpenFile(file, arrow::default_memory_pool(), &reader));

    std::shared_ptr<arrow::Table> parquet_table;
    PARQUET_THROW_NOT_OK(reader->ReadTable(&parquet_table));
 
    std::cout << "Table Data:\n";
    std::cout << parquet_table->ToString() << std::endl;

    return arrow::Status::OK();
}

int main() {
    arrow::Status st = RunMain();
    if (!st.ok()) {
        std::cerr << st << std::endl;
        return 1;
    }
    return 0;
}

但换成Snappy压缩的Parquet文件时,控制台输出乱码。该压缩文件是用Python的pandas生成的(pandas.dataframe.to_parquet默认用Snappy压缩):

b = pd.DataFrame([[1,2,3,4],[2,2,3,4],[4,5,6,7],[9,10,11,101]])
b.to_parquet('b.parquet')

如果在Python代码里设置compression=None生成未压缩文件,C++代码就能正常运行。现在想知道:如何读取大量已压缩的Parquet文件?

解决方案

1. 确保Arrow/Parquet库编译时包含Snappy压缩支持

乱码问题本质是你的C++版Arrow/Parquet库未编译Snappy压缩支持,导致无法正确解码Snappy压缩的Parquet数据,进而输出乱码。

  • 自行编译Arrow库时,需要在CMake编译阶段添加-DARROW_WITH_SNAPPY=ON参数,同时确保系统已安装Snappy依赖(如Ubuntu下执行sudo apt-get install libsnappy-dev,CentOS下执行yum install snappy-devel)。编译Parquet库时,需依赖已开启Snappy支持的Arrow库。
  • 使用预编译包时,选择包含Snappy支持的版本,比如通过conda安装:conda install -c conda-forge arrow-cpp parquet-cpp snappy。

2. 原代码无需修改,验证Snappy支持

当库正确包含Snappy支持后,你现有的C++代码不需要任何修改,即可正常读取Snappy压缩的Parquet文件。建议先单文件测试,确认乱码问题消失。

3. 批量读取大量压缩Parquet文件的优化方法

处理大量Parquet文件时,可参考以下优化方式:

  • 批量遍历文件:使用C++17及以上的<filesystem>库遍历目标目录下的所有.parquet文件。
  • 并行读取:利用Arrow的线程池(arrow::ThreadPool)分发读取任务,提升处理效率。
  • 分块读取:针对大文件,不要一次性读取整个表,而是用reader->ReadRowGroup(row_group_idx, &table)按行组读取,降低内存占用。
  • 合并表(可选):若需将多个文件的数据合并为一个表,可使用arrow::ConcatenateTables函数合并读取到的多个arrow::Table。

批量读取目录下Parquet文件的简化代码片段:

#include <filesystem>
#include <vector>

namespace fs = std::filesystem;

arrow::Status ReadAllParquet(const std::string& dir_path, std::vector<std::shared_ptr<arrow::Table>>& tables) {
    for (const auto& entry : fs::directory_iterator(dir_path)) {
        if (entry.path().extension() == ".parquet") {
            std::shared_ptr<arrow::io::ReadableFile> file;
            ARROW_ASSIGN_OR_RAISE(file, arrow::io::ReadableFile::Open(entry.path().string()));
            
            std::unique_ptr<parquet::arrow::FileReader> reader;
            PARQUET_THROW_NOT_OK(parquet::arrow::OpenFile(file, arrow::default_memory_pool(), &reader));
            
            std::shared_ptr<arrow::Table> table;
            PARQUET_THROW_NOT_OK(reader->ReadTable(&table));
            tables.push_back(table);
        }
    }
    return arrow::Status::OK();
}

内容的提问来源于stack exchange,提问作者DennisDai

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 15:33:28