在delphi中直接访问文件

时间:2009-02-06 11:11:07

标签: delphi file-access

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

此刻我将文件加载到动态数组中做我需要做的所有事情然后将其保存回来......这看起来很好,直到我进入我的测试阶段,我发现转换了多个千兆字节的文件有128mb 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;

我需要的是直接文件访问以最小化ram使用..这就是我认为我需要/ 这是我需要的,可以在delphi中完成

5 个答案:

答案 0 :(得分: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;

答案 1 :(得分:2)

您还可以将文件的各个部分直接映射到内存中。这绝对是最直接的方式。有关示例,请参阅What is the fastest way to Parse a line in Delphi

答案 2 :(得分:1)

如果问题允许,您可以使用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);

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

答案 3 :(得分: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;

这种方法的唯一问题是它只适用于固定大小的结构,可变长度字符串需要不同的方法。

答案 4 :(得分:0)

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