Какую функцию C ++ Write я должен использовать? - PullRequest
0 голосов
/ 24 декабря 2011

Я предпочитаю не использовать синтаксический анализатор библиотеки XML, так что вы можете дать мне совет, какую хорошую функцию записи использовать для записи данных в файл XML?Я сделаю много вызовов функции записи, чтобы функция записи могла отслеживать последнюю позицию записи и не должна занимать слишком много ресурсов.У меня есть две разные записи ниже, но я не могу отслеживать последнюю позицию записи, если мне не нужно прочитать файл до конца файла.

case # 1

FILE *pfile = _tfopen(GetFileNameXML(), _T("w"));

if(pfile)
{
    _fputts(TEXT(""), pfile);
}

if(pfile)
{
    fclose(pfile);
    pfile = NULL;
}

case # 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);

спасибо.

Ответы [ 2 ]

2 голосов
/ 24 декабря 2011

Если все, что вам нужно, это написать несколько текстовых файлов, используйте стандартные средства библиотеки C ++. Примеры здесь будут полезны: http://www.cplusplus.com/doc/tutorial/files/

0 голосов
/ 24 декабря 2011

Во-первых, каково ваше отвращение к использованию стандартной библиотеки обработки XML?

Далее, если вы решите свернуть свою собственную, определенно не обращайтесь напрямую к Win32 API - по крайней мере, если вы несобираемся записывать сгенерированный XML большими кусками, или вы собираетесь реализовать свой собственный уровень буферизации.

Это не имеет значения для работы с крошечными файлами, но вы особо упомянули хорошую производительность и много обращений кфункция записи.WriteFile требует значительных накладных расходов, выполняет много работы и включает переключатели режима user-> kernel-> user, которые стоят дорого.Если вы имеете дело с «обычными по размеру» XML-файлами, вы, вероятно, не сможете увидеть большую разницу, но если вы создаете дампы чудовищного размера, это, безусловно, кое-что, что нужно иметь в виду.

Выупомяните отслеживание последней позиции записи - во-первых, это должно быть легко ... с буферами FILE у вас есть ftell , с необработанным Win32 API у вас есть SetFilePointerEx - вызовите его с помощью liDistanceToMove=0и dwMoveMethod=FILE_CURRENT, и вы получите текущую позицию файла после записи.Но зачем тебе это?Если вы транслируете XML-файл, вам обычно следует продолжать потоковую передачу до тех пор, пока вы не закончите запись - закрываете ли вы и снова открываете файл?Или вы пишете правильный XML-файл, в который вы хотите вставить больше данных позже?

Что касается накладных расходов на файловые функции Win32, это может или не может иметь значение в вашем случае (в зависимости от размерафайлы, с которыми вы имеете дело), ​​но для больших файлов это имеет большое значение - ниже приведен микро-эталон, который упрощает чтение файла в память с помощью ReadFile, позволяя вам указать разные размеры буфера из командной строки.Интересно, например, посмотреть на вкладку ввода-вывода Process Explorer во время работы инструмента.Вот некоторая статистика с моего жалкого ноутбука (Win7-SP1 x64, core2duo P7350 @ 2.0 ГГц, 4 ГБ оперативной памяти, 120 ГБ твердотельный накопитель Intel-320).

Примите это за микропроцессор.Производительность может или не может иметь значения в вашей конкретной ситуации, но я полагаю, что цифры демонстрируют, что существуют значительные издержки для файловых API-интерфейсов Win32, и что небольшая буферизация помогает вам.

С полностью кэшированнымФайл 2 ГБ:

BlkSz   Speed
32      14.4MB/s
64      28.6MB/s
128     56MB/s
256     107MB/s
512     205MB/s
1024    350MB/s
4096    800MB/s
32768   ~2GB/s

При значении «настолько велики будут только кешированные пропуски» файл 4 ГБ:

BlkSz   Speed       CPU
32      13MB/s      49%
64      26MB/s      49%
128     52MB/s      49%
256     99MB/s      49%
512     180MB/s     49%
1024    200MB/s     32%
4096    185MB/s     22%
32768   205MB/s     13%

Имейте в виду, что 49% использования ЦП означает, что одно ядро ​​ЦПв значительной степени полностью прикреплен - одна нить не может толкнуть машину намного сильнее.Обратите внимание на патологическое поведение буфера 4 КБ во второй таблице - он был воспроизводим, и у меня нет объяснения этому.

Слабый микропроцессорный код здесь:

#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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...