C++读取具有不同数据类型的列式存储中的 CSV 表

C++ read CSV table in columnar store with different datatypes

本文关键字:存储 CSV 数据类型 读取 C++      更新时间:2023-10-16

我想读取包含数据库表(TPCH)的CSV文件。每个文件都有不同数量的列、行和数据类型。

例如:

 file1: Int, double, char[]
 file2: double, char[], int, int 

另一个要求是每一列应该驻留在一个数组中(对于每一列一个数组 - 而不是每行)。

我的解决方案:目前我正在根据数据类型和csv文件的大小在运行时使用new创建数组

 e.g. file1: would be int[] , double[]... 

然后我将数组的起始地址存储为 map(int,void*) 中的 void*。

当我想从数组中读取值时,我必须检索 void* 并根据类型强制转换它。

正如你所看到的,我有很多顽皮的指针和投射。有没有更好的方法以列格式存储表?我想使用数组,因为我经常复制它们并通过网络传输它们。另外,我不想使用提升库。

是的,指针经常导致头痛。首先,我建议你使用STL容器,比如std::vector,它会让你的生活更轻松。不需要提升,甚至不需要新的C++编译器,因为std::vector已经存在很长时间了。

但是我不明白为什么要存储数组的起始地址。无论如何,如果你只想存储一个地址,你可以使用头文件<cstdint>并使用类型intptr_t / uintptr_t,保证能够持有void*

这是一个很好的用例 variant .在 C++17 中,我们将将其作为标准库的一部分,但现在我们坚持使用 boost 实现。

如果您不想使用boost有几个选项供您选择,但它们都至少有点恶心。

  1. void* .由于多种原因,这是不可取的。你已经知道了,所以我不会在这里深入研究。
  2. union .在处理具有构造函数和析构函数的对象时,这也是不可取的。你必须记住调用析构函数,你必须知道就地调用构造函数。比void*好,但只是勉强。假设您正在处理所有原始类型,std::vector<some_union_type>可能不会那么糟糕,但是一旦您引入了动态大小的字符串,您就会陷入一个受伤的世界。
  3. 字节操作。将所有内容存储在char[](更具体地说,std::vector<char> )中,并将有关数据类型的元数据保存在某种枚举中。使用该枚举将字节转换为正确的类型。这是一个非常棘手的解决方案,可以手工组合在一起,但它类似于通常实现variant的方式。
  4. 运行时多态性。创建一个父类,然后为每个数据类型创建一个子类。动态分配子类(将它们存储在std::unique_ptr中),并通过执行dynamic_cast将它们取出,直到获得正确的类型(或将数据类型存储在枚举中并基于此进行强制转换)。这可能是最"高级"的解决方案,并且可能比前三个解决方案更容易正确。
  5. 基于概念的多态性。这基本上是手掷any的特例(在另一个答案中提到)。肖恩·帕伦特(Sean Parent)在这里涵盖了它。对于您的情况,您可能会发现自己实现了类似variant::visitor模式的东西来获取所需的数据。

也许使用boost::variant看起来并不那么糟糕。 ;)