如何在32位系统上读取4GB文件

时间:2014-08-05 22:01:22

标签: c++ boost large-files 32-bit data-processing

在我的情况下,我有不同的文件让我们假设我有> 4GB文件的数据。我想逐行读取该文件并处理每一行。我的一个限制是软件必须在32位MS Windows上运行,或者在64位上运行少量RAM(最小4GB)。您还可以假设这些行的处理不是瓶颈。

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

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

好的,这是有效的,但在这里我的3.6 GB数据的时间很慢:

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

我正在寻找一种比这更快的方法,例如我发现How to parse space-separated floats in C++ quickly?并且我喜欢用boost :: mapped_file提供解决方案,但我面临另一个问题,如果我的文件是大的在我的情况下文件1GB大到足以放弃整个过程。我必须关心内存中的当前数据,可能使用该工具的人没有安装超过4 GB的RAM。

所以我发现了来自boost的mapped_file但是在我的情况下如何使用它?是否可以部分读取该文件并接收这些行?

也许你有另一个更好的解决方案。我必须处理每一行。

谢谢,
巴特

4 个答案:

答案 0 :(得分:6)

很高兴看到您在How to parse space-separated floats in C++ quickly?

找到了我的基准

看起来你真的在寻找最快的计算线数(或任何线性单程分析),我已经完成了类似的分析和基准测试

有趣的是,你会发现性能最高的代码根本不需要依赖内存映射。

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, '\n', (buf + bytes_read) - p)); ++p)
            ++lines;
    }

    return lines;
}

答案 1 :(得分:3)

具有小内存的64位系统的情况应该可以很好地加载一个大文件 - 这都是关于地址空间 - 虽然它可能比那个情况下的“最快”选项慢,但它真的取决于内存中还有什么内容以及可用于将文件映射到的内存量。在32位系统中,它不起作用,因为进入文件映射的指针最多不会超过大约3.5GB - 通常大约2GB是最大值 - 再次,取决于可用的内存地址将文件映射到的操作系统。

然而,内存映射文件的好处非常小 - 花费的大部分时间来自实际读取数据。使用内存映射的节省来自于在将数据加载到RAM后不必复制数据。 (当使用其他文件读取机制时,读取功能会将数据复制到提供的缓冲区中,其中内存映射文件将直接将其填充到正确的位置)。

答案 2 :(得分:0)

您可能希望增加ifstream的缓冲区 - 默认缓冲区通常很小,这会导致大量昂贵的读取。

您应该可以使用以下内容执行此操作:

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++;
}

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

How to get IOStream to perform better?

答案 3 :(得分:0)

由于这是windows,您可以使用带有“ex”后缀的本机Windows文件函数:

windows file management functions

特别是GetFileSizeEx(),SetFilePointerEx()等函数。读写函数限制为32位字节计数,读写“ex”函数用于异步I / O,而不是处理大文件。