Файл не получен, если я освобождаю экземпляр потока файлов где-нибудь? - PullRequest
2 голосов
/ 20 июля 2010

Я пытаюсь отправить файл, используя TServerSocket / TClientSocket.Файл отправляется полностью, пока я нигде не освобождаю файловый поток и нигде не имею в виду событие form.OnCreate.Если я делаю бесплатно где-нибудь, отправляется только 1 или 2 процента.

Я также должен поместить строку кода TFileStream.Create на стороне сервера OnCreate.Если я создаю поток в TForm2.ServerSocket1ClientRead, то получаю EFcreateerror: «процесс не может получить доступ к файлу, потому что он используется другим процессом».

procedure TForm2.FormCreate(Sender: TObject);
begin
    FStream := TFileStream.Create('c:\temp\log.txt', fmCreate or
    fmShareDenyWrite);
end;

procedure TForm2.ClientSocket1Connect(Sender: TObject;
    Socket: TCustomWinSocket);
var
  fs: TFileStream;

begin
    fs := TFileStream.Create('c:\log.txt', fmOpenRead);
    socket.SendStream(fs);
end;

procedure TForm2.ServerSocket1ClientRead(Sender: TObject;
    Socket: TCustomWinSocket);
var
    iLen: Integer;
    Bfr: Pointer;
begin
    iLen := Socket.ReceiveLength;
    GetMem(Bfr, iLen);
    Socket.ReceiveBuf(Bfr^, iLen);
    FStream.Write(Bfr^, iLen);
    FreeMem(bfr);
    //fstream.free
end;

Даже если я добавлю свой код, этопуть:

if fstream.Size = fstream.position then
    fstream.free

Даже тогда это доставляет мне проблемы.

Что это за странные явления?Это ошибка в Delphi?Если да, есть ли обходной путь?Если это имеет значение: я использую Delphi 2010.

Обновление : извините, я имел в виду, если я поставил свой код таким образом:

if fileSize = fstream.position then
    fstream.free

Извините, но не fstream.sizeно filesize.Я уже инициализировал размер файла как 300000 (размер файла, который будет получен).

Решено: Решено заменой

FStream := TFileStream.Create('c:\temp\log.txt',
                              fmCreate or fmShareDenyWrite);

на

if not FileExists('c:\temp\log.txt') then
    FStream := TFileStream.Create('c:\temp\log.txt',
                                  fmCreate or fmShareDenyWrite);

1 Ответ

4 голосов
/ 20 июля 2010

Вы пытаетесь освободить объект FStream, как только получите первый блок данных.Не делай этого.Этот блок обычно будет меньше полного файла, особенно если вы отправляете большой файл.Кроме того, проверка для Position = Size на принимающей стороне также бесполезна, так как она всегда будет иметь значение true, поскольку текущий Position всегда будет в конце потока.Как я уже говорил вам в другом обсуждении , вы не используете методы SendStream () и ReceiveBuf () эффективно, и отправителю необходимо отправить размер файла перед отправкой данных файла (или, альтернативно, отключиться приконец файла), чтобы получатель точно знал, когда прекратить чтение.

Редактировать: Попробуйте что-то вроде этого:

type
  TSocketBuffer = class
  public
    Stream: TStream;
    ExpectedSize: Int64;
    Data: array[0..1023] of Byte;
    DataOffset, DataSize: Integer;
    destructor Destroy; override;
  end;

  TServerSocketBuffer = class(TSocketBuffer)
  public
    FileName: String;
    destructor Destroy; override;
  end;

destructor TSocketBuffer.Destroy;
begin
  if Stream <> nil then Stream.Free;
  inherited;
end;

destructor TServerSocketBuffer.Destroy;
begin
  if Stream <> nil then FreeAndNil(Stream);
  if FileName <> '' then DeleteFile(FileName);
  inherited;
end;

procedure TForm2.ClientSocket1Connect(Sender: TObject; Socket: TCustomWinSocket); 
var
  Buffer: TSocketBuffer;
begin 
  Buffer := TSocketBuffer.Create;
  Socket.Data := Buffer;

  // open the file to send...
  Buffer.Stream := TFileStream.Create('c:\log.txt', fmOpenRead or fmShareDenyWrite); 
  Buffer.ExpectedSize := Buffer.Stream.Size;

  // buffer the stream size...
  Move(Buffer.Data[0], Buffer.ExpectedSize, Sizeof(Int64));
  Buffer.DataOffset := 0;
  Buffer.DataSize := SizeOf(Int64);

  // begin sending...
  ClientSocket1Write(Sender, Socket);
end; 

procedure TForm2.ClientSocket1Disconnect(Sender: TObject; Socket: TCustomWinSocket); 
begin 
  TSocketBuffer(Socket.Data).Free;
end; 

procedure TForm2.ClientSocket1Write(Sender: TObject; Socket: TCustomWinSocket); 
var
  Buffer: TSocketBuffer;
  NumBytes: Integer;
begin 
  // in case OnWrite is fired before OnConnect...
  if Socket.Data = nil then Exit;

  Buffer := TSocketBuffer(Socket.Data);
  if Buffer.Stream = nil then Exit;

  // keep sending until EOF is reached, or until the socket blocks/errors...
  repeat
    // if there is pending data buffered, send it now...
    while Buffer.DataOffset < Buffer.DataSize do
    begin
      NumBytes := Socket.SendBuf(Buffer.Data[Buffer.DataOffset], Buffer.DataSize-Buffer.DataOffset);
      if NumBytes <= 0 then Exit; // wait for next event...
      Inc(Buffer.DataOffset, NumBytes);
    end;

    // has EOF been reached?
    if Buffer.ExpectedSize <= 0 then Break;

    // read the next block of data from the stream...
    Buffer.DataOffset := 0;
    Buffer.DataSize := 0;
    NumBytes := Buffer.Stream.Read(Buffer.Data[0], Min(Buffer.ExpectedSize, SizeOf(Buffer.Data)));
    if NumBytes <= 0 then Break; // stream error, stop sending...
    Buffer.DataSize := NumBytes;
    Dec(Buffer.ExpectedSize, NumBytes);

    // the next loop iteration will start sending it...
  until False;

  // all done...
  FreeAndNil(Buffer.Stream);
  Socket.Close;
end; 

procedure TForm2.ServerSocket1ClientConnect(Sender: TObject; Socket: TCustomWinSocket); 
begin
  Socket.Data := TServerSocketBuffer.Create;
end;

procedure TForm2.ServerSocket1ClientDisconnect(Sender: TObject; Socket: TCustomWinSocket); 
begin
  TServerSocketBuffer(Socket.Data).Free;
end;

procedure TForm2.ServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket); 
var 
  Buffer: TServerSocketBuffer;
  FileName: String;
  NumBytes: Integer; 
begin 
  Buffer := TServerSocketBuffer(Socket.Data);

  if Buffer.Stream = nil then
  begin
    // keep reading until stream size has been received in full...

    while Buffer.DataSize < SizeOf(Int64) do
    begin
      NumBytes := Socket.ReceiveBuf(Buffer.Data[Buffer.DataOffset], SizeOf(Int64)-Buffer.DataOffset);
      if NumBytes <= 0 then Exit; // wait for next event...
      Inc(Buffer.DataSize, NumBytes);
      Inc(Buffer.DataOffset, NumBytes);
    end;

    Move(Buffer.ExpectedSize, Buffer.Data[0], SizeOf(Int64));

    // create the file to store in...
    FileName := 'c:\temp\log.txt';
    Buffer.Stream := TFileStream.Create(FileName, fmCreate);
    Buffer.FileName := FileName;

    // (optional) pre-size the file...
    Buffer.Stream.Size := Buffer.ExpectedSize;
  end;

  // keep reading until EOF is reached, or until the socket blocks/errors...
  while Buffer.ExpectedSize > 0 do
  begin
    // read the next block of data from the socket...
    Buffer.DataOffset := 0;
    Buffer.DataSize := 0;

    NumBytes := Socket.ReceiveBuf(Buffer.Data[0], Min(Buffer.ExpectedSize, SizeOf(Buffer.Data)));
    if NumBytes <= 0 then Exit; // wait for next event...

    Buffer.DataSize := NumBytes;

    // save the data to the stream....
    repeat
      NumBytes := Buffer.Stream.Write(Buffer.Data[Buffer.DataOffset], Buffer.DataSize-Buffer.DataOffset); 
      if NumBytes <= 0 then
        // stream error, stop reading...
        Socket.Close;
        Exit;
      end;
      Inc(Buffer.DataOffset, NumBytes);
      Dec(Buffer.ExpectedSize, NumBytes);
    until Buffer.DataOffset >= Buffer.DataSize;
  end;

  // all done...
  FreeAndNil(Buffer.Stream);
  Buffer.FileName := '';
end; 
...