关于使用Parquet-GLib编写Apache Parquet文件的技术咨询
关于使用Parquet-GLib编写Apache Parquet文件的技术咨询
嘿,我太懂这种对着API文档却无从下手的感觉了——光看接口定义确实很难拼凑出完整的读写流程。下面我给你整理了实操性强的代码示例和构建注意事项,帮你快速上手parquet-glib:
先搞定编译构建问题
parquet-glib基于GLib,所以编译时必须正确链接相关依赖。最省心的方式是用pkg-config自动获取编译参数,编译命令类似这样:
gcc your_parquet_code.c -o parquet_demo $(pkg-config --cflags --libs parquet-glib)
这个命令会自动包含parquet-glib和GLib的头文件路径,以及需要链接的库文件,不用手动写一堆-I和-L参数。
完整写入Parquet文件的示例
这个示例会创建一个包含id(整数)和name(字符串)两列的Parquet文件,写入两行数据:
#include <parquet-glib/parquet-glib.h> int main() { // 初始化GLib的类型系统,GLib程序必备步骤 g_type_init(); // 第一步:定义Parquet的Schema GList *schema_fields = NULL; // 创建int32类型的"id"字段 ParquetSchemaElement *id_field = parquet_schema_element_new("id", PARQUET_TYPE_INT32, 0, FALSE); schema_fields = g_list_append(schema_fields, id_field); // 创建UTF8字符串类型的"name"字段 ParquetSchemaElement *name_field = parquet_schema_element_new("name", PARQUET_TYPE_BYTE_ARRAY, 0, FALSE); parquet_schema_element_set_converted_type(name_field, PARQUET_CONVERTED_TYPE_UTF8); schema_fields = g_list_append(schema_fields, name_field); ParquetSchema *schema = parquet_schema_new(schema_fields); g_list_free(schema_fields); // 字段列表用完可以释放 // 第二步:配置写入器属性(比如压缩方式) ParquetFileWriterProperties *writer_props = parquet_file_writer_properties_new(); parquet_file_writer_properties_set_compression(writer_props, PARQUET_COMPRESSION_SNAPPY); // 第三步:创建文件写入器 ParquetFileWriter *file_writer = parquet_file_writer_new("demo_output.parquet", schema, writer_props); // 用完的资源及时释放 parquet_schema_unref(schema); parquet_file_writer_properties_unref(writer_props); // 第四步:创建行组写入器(这里预分配2行数据) ParquetRowGroupWriter *row_group = parquet_file_writer_append_row_group(file_writer, 2); // 写入id列数据 GArray *id_values = g_array_new(FALSE, FALSE, sizeof(gint32)); gint32 ids[] = {1, 2}; g_array_append_vals(id_values, ids, 2); ParquetColumnWriter *id_col_writer = parquet_row_group_writer_next_column(row_group); parquet_column_writer_write_batch(id_col_writer, 2, NULL, NULL, id_values->data, NULL); g_array_unref(id_values); parquet_column_writer_unref(id_col_writer); // 写入name列数据 GArray *name_values = g_array_new(FALSE, FALSE, sizeof(GByteArray*)); GByteArray *name_alice = g_byte_array_new(); g_byte_array_append(name_alice, (guint8*)"Alice", 5); GByteArray *name_bob = g_byte_array_new(); g_byte_array_append(name_bob, (guint8*)"Bob", 3); GByteArray *names[] = {name_alice, name_bob}; g_array_append_vals(name_values, names, 2); ParquetColumnWriter *name_col_writer = parquet_row_group_writer_next_column(row_group); parquet_column_writer_write_batch(name_col_writer, 2, NULL, NULL, name_values->data, NULL); // 逐个释放字符串的字节数组 for (guint i = 0; i < name_values->len; i++) { g_byte_array_free(g_array_index(name_values, GByteArray*, i), TRUE); } g_array_unref(name_values); parquet_column_writer_unref(name_col_writer); // 完成行组写入并释放资源 parquet_row_group_writer_close(row_group); parquet_row_group_writer_unref(row_group); // 关闭文件写入器并释放 parquet_file_writer_close(file_writer); parquet_file_writer_unref(file_writer); return 0; }
完整读取Parquet文件的示例
这个示例会读取上面生成的Parquet文件,打印出所有行的数据:
#include <parquet-glib/parquet-glib.h> int main() { g_type_init(); // 打开Parquet文件 ParquetFileReader *file_reader = parquet_file_reader_new("demo_output.parquet"); ParquetSchema *schema = parquet_file_reader_get_schema(file_reader); // 打印Schema信息(可选,方便调试) g_print("文件Schema: %s\n", parquet_schema_to_string(schema)); // 获取文件中的行组数量 gint row_group_count = parquet_file_reader_get_num_row_groups(file_reader); for (gint i = 0; i < row_group_count; i++) { ParquetRowGroupReader *row_group = parquet_file_reader_get_row_group(file_reader, i); gint row_count = parquet_row_group_reader_get_num_rows(row_group); g_print("\n第%d个行组,共%d行数据:\n", i, row_count); // 读取id列 ParquetColumnReader *id_col_reader = parquet_row_group_reader_next_column(row_group); GArray *id_values = g_array_new(FALSE, FALSE, sizeof(gint32)); g_array_set_size(id_values, row_count); parquet_column_reader_read_batch(id_col_reader, row_count, NULL, NULL, id_values->data, NULL); g_print("ID列数据: "); for (guint j = 0; j < id_values->len; j++) { g_print("%d ", g_array_index(id_values, gint32, j)); } g_print("\n"); g_array_unref(id_values); parquet_column_reader_unref(id_col_reader); // 读取name列 ParquetColumnReader *name_col_reader = parquet_row_group_reader_next_column(row_group); GArray *name_values = g_array_new(FALSE, FALSE, sizeof(GByteArray*)); g_array_set_size(name_values, row_count); parquet_column_reader_read_batch(name_col_reader, row_count, NULL, NULL, name_values->data, NULL); g_print("Name列数据: "); for (guint j = 0; j < name_values->len; j++) { GByteArray *name = g_array_index(name_values, GByteArray*, j); g_print("%s ", (gchar*)name->data); g_byte_array_free(name, TRUE); // 释放每个字符串的字节数组 } g_print("\n"); g_array_unref(name_values); parquet_column_reader_unref(name_col_reader); parquet_row_group_reader_unref(row_group); } // 释放剩余资源 parquet_schema_unref(schema); parquet_file_reader_close(file_reader); parquet_file_reader_unref(file_reader); return 0; }
几个关键注意事项
- 资源管理:parquet-glib的所有对象(比如
ParquetSchema、ParquetFileWriter)都需要调用对应的unref函数手动释放,避免内存泄漏。如果用GLib 2.36及以上版本,也可以用g_autoptr宏来自动管理资源,减少手动unref的工作量。 - Schema定义:如果需要处理嵌套结构、数组等复杂类型,只需要嵌套创建
ParquetSchemaElement即可,核心逻辑和简单类型一致,只是字段的层级关系需要对应好。 - 错误处理:上面的示例为了简洁省略了错误检查,实际开发中可以用
g_error或者检查函数返回值来处理可能的错误(比如文件打开失败、写入失败等)。
备注:内容来源于stack exchange,提问作者CptPicard
相关产品推荐
相关产品推荐

