如何使用Indy实现服务器向客户端传输文件?附请求示例
我来帮你补全基于Indy的文件传输完整实现,刚好匹配你给出的客户端请求格式,包含服务器端的文件发送逻辑和客户端的文件接收代码:
完整实现:Indy TCP 服务器向客户端传输文件
服务器端完整处理逻辑
你给出的代码片段可以扩展成包含异常处理、文件校验的完整逻辑,确保传输的可靠性:
procedure TServerMainForm.IdTCPServerExecute(AContext: TIdContext); var AStream: TFileStream; FileSize: Int64; Line, FileName: String; begin try // 读取客户端的请求指令 Line := AContext.Connection.IOHandler.ReadLn(); if Line = 'SEND_FILE' then begin // 读取客户端请求的文件名 FileName := AContext.Connection.IOHandler.ReadLn(); // 先校验文件是否存在 if FileExists(FileName) then begin // 向客户端发送"文件存在"的标识 AContext.Connection.IOHandler.WriteLn('FILE_FOUND'); // 创建文件流读取本地文件 AStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); try // 发送文件大小(用Int64支持4GB以上的大文件) FileSize := AStream.Size; AContext.Connection.IOHandler.WriteInt64(FileSize); // 发送文件内容,指定发送后不关闭流 AContext.Connection.IOHandler.WriteStream(AStream, False); // 强制刷新缓冲区,确保所有数据发送完成 AContext.Connection.IOHandler.Flush(); finally AStream.Free; end; end else begin // 文件不存在时向客户端返回错误标识 AContext.Connection.IOHandler.WriteLn('FILE_NOT_FOUND'); end; end; except on E: Exception do begin // 捕获异常并通知客户端,同时断开异常连接 AContext.Connection.IOHandler.WriteLn('ERROR: ' + E.Message); AContext.Connection.Disconnect; end; end; end;
小提示: 如果只处理小文件,也可以把WriteInt64换成WriteInteger,但客户端要对应使用ReadInteger来读取文件大小。
客户端接收文件的完整代码
对应你现有的请求代码,客户端发送请求后需要处理服务器的响应,完成文件接收和保存:
procedure TClientForm.ReceiveFileFromServer(const ServerFileName: String; const LocalSavePath: String); var ServerResponse: String; FileSize: Int64; SaveStream: TFileStream; begin try // 确保客户端已连接服务器 if not MyIdTCPClient.Connected then MyIdTCPClient.Connect; // 发送请求指令和文件名(和你现有代码完全匹配) MyIdTCPClient.IOHandler.WriteLn('SEND_FILE'); MyIdTCPClient.IOHandler.WriteLn(ServerFileName); // 读取服务器的响应 ServerResponse := MyIdTCPClient.IOHandler.ReadLn(); if ServerResponse = 'FILE_FOUND' then begin // 读取服务器发送的文件大小 FileSize := MyIdTCPClient.IOHandler.ReadInt64(); // 创建本地文件流用于保存 SaveStream := TFileStream.Create(LocalSavePath, fmCreate or fmShareDenyWrite); try // 读取服务器发送的文件内容到本地 MyIdTCPClient.IOHandler.ReadStream(SaveStream, FileSize, False); ShowMessage('文件接收完成!已保存到:' + LocalSavePath); finally SaveStream.Free; end; end else if ServerResponse = 'FILE_NOT_FOUND' then begin ShowMessage('服务器上不存在文件:' + ServerFileName); end else if StartsText('ERROR:', ServerResponse) then begin ShowMessage('传输出错:' + Copy(ServerResponse, 7, Length(ServerResponse))); end; except on E: Exception do begin ShowMessage('接收文件失败:' + E.Message); if MyIdTCPClient.Connected then MyIdTCPClient.Disconnect; end; end; end;
调用示例: 如果你要获取服务器上的1.XLS并保存到本地C:\Downloads\1.XLS,可以这样调用:
ReceiveFileFromServer('1.XLS', 'C:\Downloads\1.XLS');
关键注意事项
- 确保客户端和服务器的
IOHandler.ReadLn()使用相同编码,如果要支持中文文件名,需要在两端设置IOHandler.DefStringEncoding := IndyTextEncoding_UTF8; - 传输大文件时,可以在服务器端添加进度反馈逻辑(比如定期发送已传输字节数),客户端据此显示进度条提升体验
- 生产环境建议添加身份校验逻辑,避免非法客户端请求服务器文件
内容的提问来源于stack exchange,提问作者Pele
相关产品推荐
相关产品推荐

