1

私のアプリケーションはファイルを開き、変換を行い、データを別のファイルに保存します..または同じファイルの可能性があります..ファイルサイズは変更されますが、最初のファイル内のデータが表示されるまで、そのゴナがどれほど大きいか小さいかわかりません..

現時点では、ファイルを動的配列にロードし、そこで必要なすべてのことを行ってから保存します...これは、128MBのシステムでマルチギガバイトのファイルを変換することがわかったテスト段階に到達するまでは良さそうでしたRAMはいくつかの問題を引き起こしました...LOLは私のコードです..

procedure openfile(fname:string);
var
  myfile: file;
  filesizevalue:integer;
begin
  AssignFile(myfile,fname);
  filesizevalue := GetFileSize(fname);
  Reset(myFile, 1);
  SetLength(dataarray, filesizevalue);
  BlockRead(myFile, dataarray[0], filesizevalue);
  CloseFile(myfile);
end;

私が必要としているのは、RAM の使用を最小限に抑えるためのファイルへの直接アクセスです。

4

5 に答える 5

3

おそらくバッファリングを備えた TFileStream を使用することを検討しますが、最善の戦略を決定するのは難しいため、実際にデータで何をしているのかを示す必要があります。gabr が言うように、1 つのオプションはメモリ マップ ファイルです。そのコードは彼のリンクにありますが、それは私のコードなので、ここにも追加します。

procedure TMyReader.InitialiseMapping(szFilename : string);
var
//  nError : DWORD;
    bGood : boolean;
begin
    bGood := False;
    m_hFile := CreateFile(PChar(szFilename), GENERIC_READ, 0, nil, OPEN_EXISTING, 0, 0);
    if m_hFile <> INVALID_HANDLE_VALUE then
    begin
        m_hMap := CreateFileMapping(m_hFile, nil, PAGE_READONLY, 0, 0, nil);
        if m_hMap <> 0 then
        begin
            m_pMemory := MapViewOfFile(m_hMap, FILE_MAP_READ, 0, 0, 0);
            if m_pMemory <> nil then
            begin
                    htlArray := Pointer(Integer(m_pMemory) + m_dwDataPosition);
                    bGood := True;
            end
            else
            begin
 //                      nError := GetLastError;
            end;
       end;
    end;
    if not bGood then
        raise Exception.Create('Unable to map token file into memory');
end;
于 2009-02-06T12:22:01.297 に答える
2

ファイルの一部をメモリに直接マップすることもできます。それは間違いなく最も直接的な方法です。例については、「 Delphi で行を解析する最速の方法は何ですか」を参照してください。

于 2009-02-06T11:32:04.720 に答える
1

この種の処理にはtFileStreamを使用することを好みます。この例では、単一の配列要素のサイズに設定された定数ArraySizeがあると想定しています。たとえば、「配列」が整数の配列である場合、次のように設定されます。

ArraySize := SizeOf( Integer );

これにより、ArraySizeが4に設定されます。

Function LoadPos(inFIlename:string;ArrayPos:Int64;var ArrayBuff) : boolean;
var
  fs : tFileStream;
begin
  result := false;
  fs := tFileStream.Create(inFilename,fmOpenRead);
  try
    // seek to the array position
    fs.Seek( ArrayPos * ArraySize, soFromBeginning);
    // load the element
    result := fs.Read( ArrayBuff, ArraySize ) = ArraySize;
  finally
    fs.free;
  end;
end;

このアプローチの唯一の問題は、固定サイズの構造でのみ機能することです。可変長の文字列には別のアプローチが必要です。

于 2009-02-06T17:12:44.110 に答える
1

問題が許せば、 and を使用BlockReadBlockWriteて入力ファイルのチャンクを読み取り、処理してから、そのチャンクを出力ファイルに書き込むことができます。このようなもの:

  AssignFile(inFile,inFname); 
  AssignFile(outFile,outFname); 
  repeat      
    BlockRead(inFile, buff, SizeOf(buff), bytesRead);
    ProcessBuffer(buff);
    BlockWrite(outFile, buff, bytesRead, bytesWritten);
  until (bytesRead = 0) or (bytesWritten <> bytesRead);

コードは、処理中にバッファのサイズを変更しないことを前提としています。ファイルのサイズが変更された場合は、サンプル コードの最後の 2 行を変更する必要があります。

于 2009-02-06T12:44:30.720 に答える
0

「より直接的な」ファイルアクセスが得られるとは思いません。ファイル内のすべてのデータを使用しますか? それ以外の場合は、おそらくストリームを使用して、必要なデータのみをメモリにロードできます。しかし、すべてのデータを使用する場合、IMHO の解決策は 1 つだけです。ファイルをチャンクで読み取ることです。ただし、それは適用する変換の種類に大きく依存します。変換がローカルでない場合 (結合されたデータ要素がすべて同じチャンクにある場合)、問題が発生します。

于 2009-02-06T11:14:58.980 に答える