我应该使用什么c++ Write函数

What C++ Write function should I use?

本文关键字:Write 函数 c++ 什么 我应该      更新时间:2023-10-16

我不喜欢使用XML库解析器,所以你能给我建议用哪个好的写函数来写数据到XML文件吗?我将对write函数进行大量的调用,因此write函数应该能够跟踪最后的写入位置,并且它不应该占用太多资源。我在下面有两个不同的写入,但我不能跟踪最后一个写入位置,除非我必须读取文件直到文件结束。

案例# 1

FILE *pfile = _tfopen(GetFileNameXML(), _T("w"));
if(pfile)
{
    _fputts(TEXT(""), pfile);
}
if(pfile)
{
    fclose(pfile);
    pfile = NULL;
}

案例# 2

HANDLE hFile = CreateFile(GetFileNameXML(), GENERIC_READ|GENERIC_WRITE,
    FILE_SHARE_WRITE|FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(hFile != INVALID_HANDLE_VALUE)
{
    WriteFile(hFile,,,,,);
}
CloseHandle(hFile);

谢谢。

如果您所需要的只是编写一些文本文件,请使用c++的标准库文件工具。下面的示例很有帮助:http://www.cplusplus.com/doc/tutorial/files/

首先,您不喜欢使用标准XML处理库的原因是什么?

接下来,如果你决定自己开发,绝对不要直接使用Win32 api——至少除非你要把生成的XML大块大块地写出来,或者你要实现你自己的缓冲层。

对于处理小文件来说,这并不重要,但是您特别提到了良好的性能和对write函数的多次调用。WriteFile有相当多的开销,它做了很多工作,并且涉及到用户->内核->用户模式切换,这是非常昂贵的。如果您处理的是"正常大小"的XML文件,您可能看不出太大的区别,但如果您生成的是超大大小的转储文件,这绝对是要记住的事情。

你提到跟踪最后一个写入位置-首先,它应该很容易…与文件缓冲区,你有ftell,与原始的Win32 API,你有SetFilePointerEx -调用它与liDistanceToMove=0dwMoveMethod=FILE_CURRENT,你得到当前文件的位置后写。但你为什么需要这个?如果要输出一个XML文件,通常应该继续流式传输,直到完成写入—是否关闭并重新打开该文件?或者您正在编写一个稍后想要插入更多数据的有效XML文件?

至于Win32文件函数的开销,它可能与您的情况有关,也可能与您的情况无关(取决于您正在处理的文件的大小),但是对于较大的文件,它非常重要-下面包含的是一个微基准测试,它使用ReadFile简单地将文件读入内存,允许您从命令行指定不同的缓冲区大小。在运行该工具时,查看Process Explorer的IO选项卡会很有趣。以下是我的小笔记本电脑(Win7-SP1 x64, core2duo P7350@2.0GHz, 4GB ram, 120GB Intel-320 SSD)的一些统计数据。

就当它是一个微基准吧。在您的特定情况下,性能可能很重要,也可能不重要,但我相信这些数字表明Win32文件api有相当大的开销,并且您自己做一点缓冲是有帮助的。

使用完全缓存的2GB文件:

<>之前BlkSz速度32 14.4 mb/s64年28.6 mb/s128 56 mb/s256 107 mb/s512 205 mb/s1024 350 mb/s4096 800 mb/s32768 ~ 2 gb/s之前

使用"so big there will only be cache misses" 4GB文件:

<>之前BlkSz速度CPU32 13MB/s 49%64 26MB/s 49%128 52MB/s 49%25699mb/s 49%512 180MB/s 49%1024 200MB/s 32%4096 185MB/s 22%32768 205MB/s 13%之前

请记住,49%的CPU使用率意味着一个CPU核心几乎完全固定-单个线程不能真正使机器更加困难。请注意第二个表中4kb缓冲区的异常行为——它是可重复的,我对此没有任何解释。

蹩脚的微基准代码在这里:

#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <iostream>
#include <string>
#include <assert.h>
unsigned getDuration(FILETIME& timeStart, FILETIME& timeEnd)
{
    // duration is in 100-nanoseconds, we want milliseconds
    // 1 millisecond = 1000 microseconds = 1000000 nanoseconds
    LARGE_INTEGER ts, te, res;
    ts.HighPart = timeStart.dwHighDateTime; ts.LowPart = timeStart.dwLowDateTime;
    te.HighPart = timeEnd.dwHighDateTime; te.LowPart = timeEnd.dwLowDateTime;
    res.QuadPart = ((te.QuadPart - ts.QuadPart) / 10000);
    assert(res.QuadPart < UINT_MAX);
    return res.QuadPart;
}
int main(int argc, char* argv[])
{
    if(argc < 2) {
        puts("Syntax: ReadFile [filename] [blocksize]");
        return 0;
    }
    char *filename= argv[1];
    int blockSize = atoi(argv[2]);
    if(blockSize < 1) {
        puts("Please specify a blocksize larger than 0");
        return 1;
    }
    HANDLE hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0);
    if(INVALID_HANDLE_VALUE == hFile) {
        puts("error opening input file");
        return 1;
    }
    std::vector<char> buffer(blockSize);
    LARGE_INTEGER fileSize;
    if(!GetFileSizeEx(hFile, &fileSize)) {
        puts("Failed getting file size.");
        return 1;
    }
    std::cout << "File size " << fileSize.QuadPart << ", that's " << (fileSize.QuadPart / blockSize) << 
        " blocks of " << blockSize << " bytes - reading..." << std::endl;
    FILETIME dummy, kernelStart, userStart;
    GetProcessTimes(GetCurrentProcess(), &dummy, &dummy, &kernelStart, &userStart);
    DWORD ticks = GetTickCount();
    DWORD bytesRead = 0;
    do {
        if(!ReadFile(hFile, &buffer[0], blockSize, &bytesRead, 0)) {
            puts("Error calling ReadFile");
            return 1;
        }
    } while(bytesRead == blockSize);
    ticks = GetTickCount() - ticks;
    FILETIME kernelEnd, userEnd;
    GetProcessTimes(GetCurrentProcess(), &dummy, &dummy, &kernelEnd, &userEnd);
    CloseHandle(hFile);
    std::cout << "Reading with " << blockSize << " sized blocks took " << ticks << "ms, spending " <<
        getDuration(kernelStart, kernelEnd) << "ms in kernel and " << 
        getDuration(userStart, userEnd) << "ms in user mode. Hit enter to countinue." << std::endl;
    std::string dummyString;
    std::cin >> dummyString;
    return 0;
}