Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 19.11.2011, 11:03   #1
Warn
Форумчанин
 
Аватар для Warn
 
Регистрация: 03.11.2011
Сообщений: 230
По умолчанию TFileStream есть ли у него указатель на данные?

Использую TFileStream.
Нужно получить указатель на данные загруженного файла.
как это сделать? что бы поясню(см. кода ниже) не пользоваться доп. переменной bindata для заливки данных в буфер, т.е. не переливать 20 раз данные)

Код:
procedure loadmodel(const name:string; out vertexBuffer:IDirect3DVertexBuffer9);
const
	VertexSize:cardinal = 20;
var
  binfile : TFileStream;
  bindata : Pointer;
  VertexBufferMem : Pointer;
  VertexCount: Cardinal;
begin
  binfile:=TFileStream.Create(name, fmOpenRead);

  GetMem(bindata, binfile.Size);

  binfile.ReadBuffer(bindata^, binfile.Size);
  VertexCount := round(binfile.Size / VertexSize); {xyz + st}

  device.CreateVertexBuffer(binfile.Size, 0, D3DFVF_XYZ or D3DFVF_TEX1, D3DPOOL_DEFAULT, vertexBuffer, nil );
  vertexBuffer.Lock(0, binfile.Size, VertexBufferMem, 0);
  move(bindata^, VertexBufferMem^, binfile.Size);
  vertexBuffer.Unlock();
  FreeMem(bindata);
  binfile.Destroy;
  VertexBufferMem := nil;

end;
Warn вне форума Ответить с цитированием
Старый 19.11.2011, 11:18   #2
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

TFileStream не грузит данные в память.
можете разве что TMemoryStream+его метод LoadFromFile+его свойство Memory.
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 19.11.2011, 11:20   #3
haruhi
Форумчанин
 
Аватар для haruhi
 
Регистрация: 05.10.2011
Сообщений: 368
По умолчанию

TFileStream не позволяет такое. этот класс осуществляет чтение на лету и никакого собственного буфера не держит. как вариант можно использовать TMemoryStream но это тотже GetMem(bindata, binfile.Size); только сбоку.

самый хороший вариант создать свой класс потомок от TFileStream, типа TMyFileStream и в нём осущесвить данный функционал
Не стоит будить спящего Бога! (с) Меланхолия Харухи Судзумии
haruhi вне форума Ответить с цитированием
Старый 19.11.2011, 11:22   #4
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

Цитата:
самый хороший вариант создать свой класс потомок от TFileStream, типа TMyFileStream и в нём осущесвить данный функционал
учитывая что грузится сразу весь файл, не вижу разницы от TMemoryStream+LoadFromFile.
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 19.11.2011, 11:40   #5
Warn
Форумчанин
 
Аватар для Warn
 
Регистрация: 03.11.2011
Сообщений: 230
По умолчанию

Спасибо всем, теперь более жизненно смотрится)

Код:
procedure loadmodel(const name:string; out vertexBuffer:IDirect3DVertexBuffer9);
var
  VertexBufferMem : Pointer;
  Data:TMemoryStream;
begin
  Data:=TMemoryStream.Create();
  Data.LoadFromFile(name);
  Device.CreateVertexBuffer(Data.Size, 0, D3DFVF_XYZ or D3DFVF_TEX1, D3DPOOL_DEFAULT, vertexBuffer, nil );
  VertexBuffer.Lock(0, Data.Size, VertexBufferMem, 0);
  Move(Data.Memory^, VertexBufferMem^, Data.Size);
  VertexBuffer.Unlock();
  Data.Destroy;
end;
Warn вне форума Ответить с цитированием
Старый 19.11.2011, 11:55   #6
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

Код:
procedure loadmodel(const name:string; out vertexBuffer:IDirect3DVertexBuffer9);
var
  binfile : TFileStream;
  VertexBufferMem : Pointer;
  VertexCount: Cardinal;
begin
  binfile:=TFileStream.Create(name, fmOpenRead);
  device.CreateVertexBuffer(binfile.Size, 0, D3DFVF_XYZ or D3DFVF_TEX1, 3DPOOL_DEFAULT, vertexBuffer, nil );
  vertexBuffer.Lock(0, binfile.Size, VertexBufferMem, 0);
  binfile.ReadBuffer(VertexBufferMem,binfile.size);
  vertexBuffer.Unlock();
  binfile.Free;
end;
а так эффективнее.
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 19.11.2011, 12:29   #7
Warn
Форумчанин
 
Аватар для Warn
 
Регистрация: 03.11.2011
Сообщений: 230
По умолчанию

Код:
procedure loadmodel(const name:string; out vertexBuffer:IDirect3DVertexBuffer9);
var
  VertexBufferMem : Pointer;
  Data:TFileStream;
begin
  Data:=TFileStream.Create(name, fmOpenRead);
  Device.CreateVertexBuffer(Data.Size, 0, D3DFVF_XYZ or D3DFVF_TEX1, D3DPOOL_DEFAULT, vertexBuffer, nil );
  VertexBuffer.Lock(0, Data.Size, VertexBufferMem, 0);
  Data.ReadBuffer(VertexBufferMem^, Data.Size);
  VertexBuffer.Unlock();
  Data.Destroy;
end;
спасибо, думаю предел совершенства достигнут?)
Warn вне форума Ответить с цитированием
Старый 19.11.2011, 12:32   #8
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

ну в общем то да, предел.
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 19.11.2011, 18:46   #9
GunSmoker
Старожил
 
Регистрация: 13.08.2009
Сообщений: 2,581
По умолчанию

Цитата:
Нужно получить указатель на данные загруженного файла
Такого просто не может быть. Чтобы был указатель на данные - эти данные должны быть в памяти. Но файл может быть больше, чем есть памяти у программы.

Что можно сделать - проецировать файл по частям.

Например:

Код:
type
  TFileMappingStream = class(THandleStream)
  strict private
    FFileName: string;
    FMode: Word;
    FMapping: THandle;
    FData: Pointer;
    FDataSize: NativeUInt;
    procedure CheckOpen;
    procedure OpenFileMapping;
    procedure CloseFileMapping;
  public
    constructor Create(const AFileName: string; AMode: Word); overload;
    constructor Create(const AFileName: string; AMode: Word; AObsoleteDoNotUse: Cardinal); overload;
    destructor Destroy; override;
    property FileName: string read FFileName;

    property Memory: Pointer read FData;
    property MemSize: NativeUInt read FDataSize;
    procedure Map(const AOffset: UInt64; const ASize: NativeUInt);
    procedure UnMap;
  end;

{ TFileMappingStream }

constructor TFileMappingStream.Create(const AFileName: string; AMode: Word);
begin
  Create(AFilename, AMode, 0);
end;

constructor TFileMappingStream.Create(const AFileName: string; AMode: Word;
  AObsoleteDoNotUse: Cardinal);
var
  Mode: Word;
begin
  FMode := AMode;
  Mode := AMode;
  if (Mode and fmCreate) = fmCreate then
  begin
    Mode := Mode and $FF;
    if Mode = $FF then
      Mode := fmShareExclusive; // For compat in case $FFFF passed as Mode
    inherited Create(FileCreate(AFileName, Mode, AObsoleteDoNotUse));
    if FHandle = INVALID_HANDLE_VALUE then
      raise EFCreateError.CreateFmt(SFCreateErrorEx, [ExpandFileName(AFileName), SysErrorMessage(GetLastError)]);
  end
  else
  begin
    // CreateFileMapping doesn't support "write only", so replace with R&W
    if (Mode and fmOpenWrite) = fmOpenWrite then
      Mode := (Mode and (not fmOpenWrite)) or fmOpenReadWrite;
    inherited Create(FileOpen(AFileName, Mode));
    if FHandle = INVALID_HANDLE_VALUE then
      raise EFOpenError.CreateFmt(SFOpenErrorEx, [ExpandFileName(AFileName), SysErrorMessage(GetLastError)]);
  end;
  FFileName := AFileName;
end;

destructor TFileMappingStream.Destroy;
begin
  if FMapping <> 0 then
    CloseFileMapping;
  if FHandle <> INVALID_HANDLE_VALUE then
  begin
    FileClose(FHandle);
    FHandle := 0;
  end;
  inherited Destroy;
end;

procedure TFileMappingStream.CheckOpen;
begin
  if FMapping = 0 then
    OpenFileMapping;
end;

procedure TFileMappingStream.OpenFileMapping;
var
  Mode: Cardinal;
begin
  if (FMode and fmOpenRead) = fmOpenRead then
    Mode := PAGE_READONLY
  else
    Mode := PAGE_READWRITE;
  FMapping := CreateFileMapping(Handle, nil, Mode, 0, 0, nil);
  Win32Check(FMapping <> 0);
end;

procedure TFileMappingStream.CloseFileMapping;
begin
  UnMap;
  CloseHandle(FMapping);
end;

procedure TFileMappingStream.Map(const AOffset: UInt64; const ASize: NativeUInt);
var
  Sz: LARGE_INTEGER;
  Mode: Cardinal;
begin
  CheckOpen;
  UnMap;

  if (FMode and fmOpenRead) = fmOpenRead then
    Mode := FILE_MAP_READ
  else
  if (FMode and fmOpenWrite) = fmOpenWrite then
    Mode := FILE_MAP_WRITE
  else
    Mode := FILE_MAP_READ or FILE_MAP_READ;
  Sz.QuadPart := AOffset;
  FData := MapViewOfFile(FMapping, Mode, Sz.HighPart, Sz.LowPart, ASize);
  Win32Check(Assigned(FData));
  FDataSize := ASize;
end;

procedure TFileMappingStream.UnMap;
begin
  if FData <> nil then
  begin
    UnmapViewOfFile(FData);
    FData := nil;
  end;
  FDataSize := 0;
end;
Использование:
Код:
procedure TForm1.Button1Click(Sender: TObject);
var
  FS: TFileMappingStream;
  Str: String;
begin
  // Как обычный поток:
  FS := TFileMappingStream.Create('Test.bin', fmCreate or fmShareExclusive);
  try
    Str := 'Test string';
    FS.WriteBuffer(Str[1], (Length(Str) + 1) * SizeOf(Char));
  finally
    FreeAndNil(FS);
  end;

  // Как проекцию файла:
  FS := TFileMappingStream.Create('Test.bin', fmOpenRead or fmShareDenyWrite);
  try
    FS.Map(0, 0);
    Caption := PChar(FS.Memory);
  finally
    FreeAndNil(FS);
  end;
end;
Правда, в вашем случае большого смысла в этом нет, т.к. данные всё равно надо будет отдавать "на сторону", так что без их загрузки/копирования не обойтись в любом случае.

Но как общий пример - вполне себе можно.
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
GunSmoker вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Как можно закрепить за окном класс(указатель на него) Warn Общие вопросы Delphi 7 06.11.2011 15:05
TMemoryStream и TFileStream есть ли различия? Crystallon Общие вопросы Delphi 8 01.09.2011 02:24
Есть окно, в котором есть аналог Memo. Как из него вытащить текст? TwiX Общие вопросы Delphi 6 16.06.2011 13:58
Есть код.Поиск ошибки.указатель this -ushёl- Общие вопросы C/C++ 3 11.07.2010 19:39