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

C++ 如何在32位系统上读取4GB文件,c++,boost,large-files,32-bit,data-processing,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; whil

在我的例子中,我有不同的文件,让我们假设我有>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
我正在寻找一种比这快得多的方法,例如,我发现了这个方法,并且我喜欢使用boost::mapped_文件提供的解决方案,但我面临另一个问题,如果我的文件太大,并且在我的情况下,文件1GB大到足以删除整个过程,该怎么办。我必须关心内存中的当前数据,可能使用该工具的人安装的RAM不超过4GB

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

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

谢谢,

Bart

对于内存较小的64位系统,可以将大文件加载到内存中—这都是关于地址空间的—尽管在这种情况下,它可能比“最快”选项慢,但这实际上取决于内存中还有什么,以及有多少内存可用于将文件映射到内存中。在32位系统中,它将不起作用,因为文件映射的指针最多不会超过3.5GB(通常最大为2GB),这取决于操作系统可将文件映射到的内存地址


然而,对文件进行内存映射的好处很小——所花费的绝大多数时间都来自于实际读取数据。使用内存映射的节省来自于数据加载到RAM后不必复制数据。(当使用其他文件读取机制时,read函数将数据复制到提供的缓冲区中,在缓冲区中,映射文件的内存将直接将其填充到正确的位置)

您可能需要考虑增加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++;
}
有关更多信息,请参见此问题:


很高兴看到您在

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

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

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

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


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

您只能映射部分文件。memmapping会将整个文件映射到内存空间。这是不可能的,因为您的文件会占用整个进程的可寻址空间。您需要“窗口”文件,以便在任何给定时间都只能通过memmap区域看到文件的较小部分。如果连续运行两次,统计数据是多少?几乎没有用户或系统时间这一事实意味着大部分时间都花在I/O上。除非您有足够的内存缓存整个文件,否则访问内存映射文件不会提高速度(因为数据需要分页)。典型的7200 rpm主轴磁盘驱动器最多只能以60 MB/秒的速度读取。3.6 GB需要1分钟的读取时间,无论您编写何种代码。您需要一个更快的磁盘,或者停止等待程序完成。@bioky-如果磁盘未被使用,但数据来自文件系统缓存,并且机器有足够的RAM,则速度会快得多。当您重复运行一个程序时,这是一个典型的基准测试风险。我将尝试在x64上编译映射,也许系统会通过分页完成其余的工作。但从另一方面来说,我认为直接使用文件窗口的方式仍然是好的。在这个想法中,我可以更改一些处理内容,以省略文件中的大量字节,这可能会快一点。你怎么认为?