如果我在任何地方释放文件流实例,则未收到文件?

发布于 2024-09-10 07:55:46 字数 1835 浏览 5 评论 0原文

我正在尝试使用 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的一个bug吗?如果是的话有没有 解决方法?如果重要的话:我正在使用 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);

I am trying to send a file using TServerSocket/TClientSocket. The file is sent completely as long as I do not free the filestream anywhere and by anywhere I mean form.OnCreate event too. If I do free anywhere only 1 or 2 percent is sent.

I also have to put the TFileStream.Create line of code on the server side OnCreate event. If I create a stream in TForm2.ServerSocket1ClientRead then I get an EFcreateerror: 'the process cannot access file because it is being used by another process''.

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;

Even if I put my code this way:

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

Even then it gives me problem.

What is this strange phenomena? Is it a bug in Delphi? If yes is there a
work-around? If it matters: I am using Delphi 2010.

Update: sorry I meant if I put my code this way:

if fileSize = fstream.position then
    fstream.free

Sorry, not fstream.size but filesize. I have already initialised file size as 300000 (size of file to be received).

Solved: Solved by replacing

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

with

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

如歌彻婉言 2024-09-17 07:55:47

您试图在收到第一个数据块后立即释放 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; 

You are trying to free your FStream object as soon as you receive the first block of data. Do not do that. That block will usually be smaller than the full file, especially if you are sending a large file. Also, checking for Position = Size on the receiving end is useless as well, as it will always evaluate be true since the current Position will always be at the end of the stream. As I already told you in the other discussion, you are not using the SendStream() and ReceiveBuf() methods effectively, and the sender needs to send the file size before sending the file data (or alternatively disconnect at the end of the file) so the receiver knows exactly when to stop its reading.

Edit:
Try something like this:

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; 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文