2011-12-24 9 views
0

私はそこにXMLライブラリパーサーを使用しないことを好むので、良い書き込み関数を使用してXMLファイルにデータを書き込むことを提案できますか?私はwrite関数の呼び出しをたくさん行うので、write関数は最後の書き込み位置を追跡できなければならず、あまりにも多くのリソースを取るべきではありません。私は以下の2つの異なる書き込みを持っていますが、ファイルの最後までファイルを読み込まなければ、最後の書き込み位置を追跡することはできません。どのようなC++書き込み関数を使用する必要がありますか?

ケース#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); 

おかげ。

+1

を否決されたのはなぜ? – Lufia

+2

私は同じことを思っていますが、私はこの質問に何が間違っているのか分かりません。本当に極端なケースでない限り、C++プログラマーは励まされるべきです。 :) –

+0

おかげでマットフィリップス。 – Lufia

答えて

-1

まず、標準的なXML処理ライブラリを使用するのはどうですか?

次に、あなた自身をロールすることを決めたなら、Win32 APIには直接行ってはいけません。少なくとも、生成されたXMLを大量のチャンクで書き出すのでなければ、あるいは実装するつもりはありません独自のバッファリングレイヤー。

小さなファイルを扱うのは問題にはなりませんが、特に優れたパフォーマンスと書き込み機能の呼び出しが多々あります。 WriteFileにはかなりのオーバーヘッドがあり、多くの作業を行い、ユーザ→カーネル→ユーザモードスイッチを必要としますが、これは高価です。 "普通のサイズの" XMLファイルを扱っているならば、おそらく大きな違いは見えませんが、大規模なダンプを生成しているなら、頭に入れておくべきことは間違いありません。

あなたが最後の書き込み位置を追跡言及 - liDistanceToMove=0dwMoveMethod=FILE_CURRENTとそれを呼び出すと、現在のファイルを取得する - 最初のオフは、それがファイルバッファを使用すると、生のWin32 APIを使用すると、SetFilePointerEx持ち、ftellを持っている...簡単にする必要があります書込み後の位置。しかし、なぜこれが必要ですか? XMLファイルをストリーミングしている場合は、通常、ストリーミングを続ける必要があります。書き終わったら、ファイルを閉じて再オープンしますか?または、後でさらにデータを挿入する有効なXMLファイルを作成していますか?

Win32ファイル関数のオーバーヘッドは、扱うファイルのサイズによっては、関連する場合とそうでない場合がありますが、ファイルが大きいほど重要ですSimpyがReadFileでメモリにファイルを読み込むマイクロベンチマークであり、コマンドラインから異なるバッファサイズを指定できるようにします。ツールを実行中にProcess ExplorerのIOタブを見るのは面白いことです。ここに私の普通のラップトップ(Win7-SP1 x64、core2duo [email protected]、4GB RAM、120GB Intel-320 SSD)からのいくつかの統計情報があります。

マイクロベンチマークであるかどうかを確認します。あなたの特定の状況では、パフォーマンスは重要ではないかもしれませんが、Win32ファイルAPIにかなりのオーバーヘッドがあり、自分自身を少しバッファリングすることで助けになることが実証されています。4GBのファイル "のみキャッシュミスが発生しますので、大きな" で

 
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 

:完全にキャッシュされた2GBのファイルで

 
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%のCPU使用率があることを意味していることを覚えておいてください1つのCPUコアがかなり完全に固定されています。単一のスレッドでは、マシンをずっと強く押すことができません。 2番目の表の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; 
} 
+1

Windowsをターゲットにして何かをファイルに書き出す単一のライブラリは、ある時点で 'WriteFile()'を呼び出すでしょう。標準のCおよびC++ファイル処理ルーチンでさえ、Windowsの 'WriteFile()'の観点から実装されています。したがって、 'WriteFile()'を直接使うことに対するあなたの批判は、Windows用のXML処理ライブラリにも適用されます。 –

+0

WriteFile()についてのヒントをありがとう。そしてあなたが参照している標準のXML処理ライブラリの名前は何ですか?私はXerces、TinyXML、CMarkupしか見ていないからです。 – Lufia

+0

@Insilico「ある時点で」、はい - 私の「非常に大きなチャンク」のコメント。小さなWriteFile呼び出しの代わりに、アプリケーション内のバッファリング(FILE *、iostream、your_own_scheme)を行うことをお勧めします。 – snemarch

関連する問題