1

我的应用程序打开文件进行转换并将数据保存到另一个文件..或者可能是同一个文件..文件大小发生变化,但我不知道它有多大或多小,直到我看到第一个文件中的数据..

目前,我将文件加载到动态数组中,然后在其中完成所有我需要做的事情,然后将其保存回来......这看起来不错,直到我进入测试阶段,在那里我发现在一个 128mb 的系统上转换多 GB 文件ram 引起了一些问题...大声笑这是我的代码..

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;

我需要的是直接文件访问以最大限度地减少内存使用..这就是我认为我需要的/这是我需要的可以在delphi中完成吗

4

5 回答 5

3

我会考虑使用 TFileStream,也许是一个带有缓冲的,但你需要真正展示你对数据所做的事情,因为很难确定最佳策略。正如 gabr 所说,一种选择是内存映射文件,其代码在他的链接中,但由于这是我的代码,我也会在这里添加它!

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

如果问题允许,您可以使用BlockReadandBlockWrite读取输入文件的块,对其进行处理,然后将该块写入输出文件。像这样的东西:

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

代码假定您在处理缓冲区时不会更改缓冲区的大小。如果文件大小发生变化,那么您应该更改示例代码的最后两行。

于 2009-02-06T12:44:30.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 回答
0

我认为您不会获得“更直接”的文件访问权限。您是否使用文件中的所有数据?否则,您也许可以使用流并仅将所需的数据加载到内存中。但是,如果您使用所有数据,恕我直言,只有一种解决方案:分块读取文件。但这在很大程度上取决于您要应用的转换类型。如果转换不是本地的(因此组合的数据元素都在同一个块中),你就会遇到问题。

于 2009-02-06T11:14:58.980 回答