You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TCP Socket接收大文件内存不足,求替代方案及FileStream适用性

TCP大文件传输问题解决方案

现有代码的核心问题

  1. 内存溢出风险:客户端用File.ReadAllBytes、服务器端用receiveMessage一次性加载整个文件到内存,大文件直接撑爆内存,导致接收不完整。
  2. 传输协议缺失:客户端定义了文件名、文件大小但没实际发送,服务器端无法知道要接收多少数据,只能依赖流结束判断,很容易出现截断。
  3. 文本格式限制:服务器用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 10:35:08