TCP Socket接收大文件内存不足,求替代方案及FileStream适用性
TCP大文件传输问题解决方案
现有代码的核心问题
- 内存溢出风险:客户端用
File.ReadAllBytes、服务器端用receiveMessage一次性加载整个文件到内存,大文件直接撑爆内存,导致接收不完整。 - 传输协议缺失:客户端定义了文件名、文件大小但没实际发送,服务器端无法知道要接收多少数据,只能依赖流结束判断,很容易出现截断。
- 文本格式限制:服务器用
File.WriteAllText写入文件,如果传输的是二进制文件(比如图片、压缩包),转成字符串会直接丢失数据。
FileStream是否合适?
完全合适。FileStream支持分块读写,不需要把整个文件加载到内存,能轻松处理GB级别的大文件,是解决大文件传输问题的标准方案。
修正后的实现代码
客户端(分块发送)
static void sendFile(string filePath, NetworkStream stream) { using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read)) { // 先发送文件名长度(4字节int),再发送文件名 string fileName = Path.GetFileName(filePath); byte[] fileNameBytes = Encoding.UTF8.GetBytes(fileName); stream.Write(BitConverter.GetBytes(fileNameBytes.Length), 0, 4); stream.Write(fileNameBytes, 0, fileNameBytes.Length); // 发送文件大小(8字节long,支持超大文件) stream.Write(BitConverter.GetBytes(fs.Length), 0, 8); // 4KB缓冲区分块发送 byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0) { stream.Write(buffer, 0, bytesRead); stream.Flush(); } } Console.WriteLine("文件发送完成"); }
服务器端(分块接收)
static void receiveFile(NetworkStream stream, TcpClient client, string op) { Console.WriteLine("Receiving file..."); // 确保存储目录存在 if (!Directory.Exists("files")) { Directory.CreateDirectory("files"); } // 读取文件名长度 byte[] lenBuffer = new byte[4]; stream.Read(lenBuffer, 0, 4); int fileNameLen = BitConverter.ToInt32(lenBuffer, 0); // 读取文件名 byte[] fileNameBytes = new byte[fileNameLen]; stream.Read(fileNameBytes, 0, fileNameLen); string fileName = Encoding.UTF8.GetString(fileNameBytes); // 读取文件总大小 byte[] sizeBuffer = new byte[8]; stream.Read(sizeBuffer, 0, 8); long totalSize = BitConverter.ToInt64(sizeBuffer, 0); // 分块写入文件 string savePath = Path.Combine("files", $"{op.ToLower()}_{fileName}"); using (FileStream fs = new FileStream(savePath, FileMode.Create, FileAccess.Write)) { byte[] buffer = new byte[4096]; long receivedBytes = 0; int bytesRead; while (receivedBytes < totalSize) { // 计算本次最多读取的字节数,避免超出剩余量 int readSize = (int)Math.Min(buffer.Length, totalSize - receivedBytes); bytesRead = stream.Read(buffer, 0, readSize); if (bytesRead == 0) break; // 连接中断,需添加异常处理 fs.Write(buffer, 0, bytesRead); receivedBytes += bytesRead; } } Console.WriteLine($"文件接收完成,保存路径:{Path.GetFullPath(savePath)}"); }
额外注意事项
- 缓冲区大小可根据网络情况调整(比如8KB、16KB),不要太大也不要太小。
- 实际部署要加异常处理,比如网络中断、文件读写失败等情况的捕获。
- 跨平台传输时要统一字节序(比如强制用大端),避免BitConverter因系统不同导致解析错误。
- 可以给TcpClient设置
ReceiveTimeout,防止无限等待无响应的连接。
内容的提问来源于stack exchange,提问作者joofil
相关产品推荐
相关产品推荐

