题
我正在尝试使用发送文件 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吗?如果是,有工作吗?如果重要的话:我使用的是德尔福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);
解决方案
你正试图释放你的 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;
不隶属于 StackOverflow