关于c ++:如何在32位系统上读取4GB文件

How to read 4GB file on 32bit system

在我的例子中,我有不同的文件,假设我有>4GB的数据文件。我想一行一行地读那个文件,然后处理每一行。我的一个限制是必须在32位MS Windows上运行Soft,或者在具有少量RAM(最小4GB)的64位上运行Soft。您还可以假设这些行的处理不是瓶颈。

在当前的解决方案中,我通过ifstream读取该文件并复制到某个字符串。下面是它的样子。

1
2
3
4
5
6
7
std::ifstream file(filename_xml.c_str());
uintmax_t m_numLines = 0;
std::string str;
while (std::getline(file, str))
{
    m_numLines++;
}

好吧,这是可行的,但是慢慢来,我的3.6GB数据是这样的:

1
2
3
real    1m4.155s
user    0m0.000s
sys     0m0.030s

我正在寻找一种方法,将比它快得多,例如我发现如何快速解析空间分离的浮点在C++中?我喜欢用boost::mapped_文件提供解决方案,但是我面临另一个问题,如果我的文件太大了,而在我的例子中,文件1GB大到足以删除整个过程。我必须关心内存中的当前数据,可能使用该工具的人安装的RAM不超过4GB。

所以我找到了Boost的映射文件,但是如何在我的案例中使用它?是否可以部分读取该文件并接收这些行?

也许你还有更好的解决办法。我必须处理每一行。

谢谢,
巴特


很高兴看到你找到了如何快速解析C++中的空间分隔浮点的基准。

似乎你真的在寻找最快的方法来计算行数(或任何线性单通分析),我在这里做了一个类似的分析和基准测试

  • C++中快速文本文件的读取

有趣的是,您将看到性能最高的代码根本不需要依赖内存映射。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
static uintmax_t wc(char const *fname)
{
    static const auto BUFFER_SIZE = 16*1024;
    int fd = open(fname, O_RDONLY);
    if(fd == -1)
        handle_error("open");

    /* Advise the kernel of our access pattern.  */
    posix_fadvise(fd, 0, 0, 1);  // FDADVICE_SEQUENTIAL

    char buf[BUFFER_SIZE + 1];
    uintmax_t lines = 0;

    while(size_t bytes_read = read(fd, buf, BUFFER_SIZE))
    {
        if(bytes_read == (size_t)-1)
            handle_error("read failed");
        if (!bytes_read)
            break;

        for(char *p = buf; (p = (char*) memchr(p, '
'
, (buf + bytes_read) - p)); ++p)
            ++lines;
    }

    return lines;
}

对于内存很小的64位系统来说,将一个大文件加载到内存中应该是很好的——这完全取决于地址空间——尽管在这种情况下,它可能比"最快"选项慢得多,但它实际上取决于内存中还有什么以及有多少内存可用于将文件映射到其中。在32位系统中,它将无法工作,因为指向文件映射的指针最多不会超过约3.5GB,通常最大值为2GB左右,这取决于操作系统可用于映射文件的内存地址。

然而,内存映射文件的好处非常小——花费的大部分时间是从实际读取数据中获得的。使用内存映射的节省是因为一旦数据加载到RAM中就不必复制数据。(当使用其他文件读取机制时,读取函数会将数据复制到提供的缓冲区中,在缓冲区中,内存映射文件会直接将其填充到正确的位置)。


因为这是Windows,所以可以使用带有"ex"后缀的本机Windows文件函数:

Windows文件管理功能

特别是像getfilesizex()、setfilepointerx()等函数….read和write函数限制为32位字节计数,read和write"ex"函数用于异步I/O,而不是处理大型文件。


您可能需要考虑增加ifstream的缓冲区——默认缓冲区通常很小,这会导致大量昂贵的读取。

您应该能够使用以下方法来完成此操作:

1
2
3
4
5
6
7
8
9
10
std::ifstream file(filename_xml.c_str());
char buffer[1024*1024];
file.rdbuf()->pubsetbuf(buffer, 1024*1024);

uintmax_t m_numLines = 0;
std::string str;
while (std::getline(file, str))
{
    m_numLines++;
}

有关详细信息,请参阅此问题:

如何让iostream表现得更好?