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

使用SMBLibrary与.NET7读取SMB文件时遭遇STATUS_END_OF_FILE异常

问题描述

使用.NET7 API结合SMBLibrary读取SMB服务器文件时,读取操作失败,返回null数据,且状态为STATUS_END_OF_FILE,需要获取文件流并上传至AWS S3存储桶。

用户提供的未完成代码:

client = new SMB2Client();
bool isConnected = client.Connect("xxxxxxxxxxx", SMBTransportType.DirectTCPTransport);
if (isConnected)
{
   NTStatus status = client.Login(string.Empty, "xxxxxxxxxx", "xxxxxxxx");
   if (status == NTStatus.STATUS_SUCCESS)
   {
     //List<string> shares = client.ListShares(out status);
     var folderPath = "folder1\\folder2\\folder3";
     var shareName = "share";

     ISMBFileStore fileStore = client.TreeConnect(shareName: shareName, out status);
     if (status == NTStatus.STATUS_SUCCESS)
     {
       object directoryHandle;
       FileStatus fileStatus;
       status = fileStore.CreateFile(out directoryHandle, out fileStatus, "", AccessMask.GENERIC_READ, 0, ShareAccess.Read | ShareAccess.Write | ShareAccess.Delete, CreateDisposition.FILE_OPEN, CreateOptions.FILE_DIRECTORY_FILE, null);
       status = fileStore.CreateFile(out directoryHandle, out fileStatus, folderPath, AccessMask.GENERIC_READ, 0, ShareAccess.Read, CreateDisposition.FILE_OPEN, CreateOptions.FILE_DIRECTORY_FILE, null);
        status = fileStore.CreateFile(out directoryHandle, out fileStatus, "file1.pdf", AccessMask.GENERIC_READ | AccessMask.SYNCHRONIZE, FileAttributes.Normal, ShareAccess.Read, CreateDisposition.FILE_OPEN, CreateOptions.FILE_NON_DIRECTORY_FILE | CreateOptions.FILE_SYNCHRONOUS_IO_ALERT, null);

        if (status == NTStatus.STATUS_SUCCESS)
        {
           MemoryStream stream = new MemoryStream();
           byte[] data;
           long bytesRead = 0;
           while (true)
           {
              status = fileStore.ReadFile(out data, directoryHandle, bytesRead, (int) client.MaxReadSize);
              //returned status :  STATUS_END_OF_FILE
解决方案

代码问题点

  1. 重复覆盖文件句柄:前两次调用CreateFile打开目录,直接覆盖了directoryHandle变量,完全没必要,直接用完整文件路径打开目标文件即可。
  2. 未处理文件末尾状态:STATUS_END_OF_FILE是读取到文件末尾的正常标记,不是错误,需要捕获并退出循环。
  3. 未写入读取数据:读取到有效数据后没写入MemoryStream,导致最终流为空。
  4. 资源未释放:SMB客户端、文件句柄等没有用using管理,容易造成资源泄漏。

修正后的完整代码

using SMBLibrary;
using SMBLibrary.Client;
using System.IO;
using Amazon.S3;
using Amazon.S3.Transfer;

// 用using自动管理SMB客户端资源
using var client = new SMB2Client();
bool isConnected = client.Connect("SMB服务器地址", SMBTransportType.DirectTCPTransport);
if (!isConnected)
{
    // 这里加连接失败的处理逻辑
    return;
}

NTStatus status = client.Login("", "用户名", "密码");
if (status != NTStatus.STATUS_SUCCESS)
{
    // 这里加登录失败的处理逻辑
    return;
}

string shareName = "share";
// 用using自动管理文件存储资源
using ISMBFileStore fileStore = client.TreeConnect(shareName, out status);
if (status != NTStatus.STATUS_SUCCESS)
{
    // 这里加共享连接失败的处理逻辑
    return;
}

// 直接用共享目录下的完整文件路径
string fullFilePath = @"folder1\folder2\folder3\file1.pdf";
object fileHandle;
FileStatus fileStatus;

// 打开目标文件
status = fileStore.CreateFile(out fileHandle, out fileStatus, fullFilePath, 
                              AccessMask.GENERIC_READ | AccessMask.SYNCHRONIZE, 
                              FileAttributes.Normal, 
                              ShareAccess.Read, 
                              CreateDisposition.FILE_OPEN, 
                              CreateOptions.FILE_NON_DIRECTORY_FILE | CreateOptions.FILE_SYNCHRONOUS_IO_ALERT, 
                              null);

if (status != NTStatus.STATUS_SUCCESS)
{
    // 这里加文件打开失败的处理逻辑
    return;
}

try
{
    using var memoryStream = new MemoryStream();
    byte[] data;
    long readOffset = 0;

    while (true)
    {
        status = fileStore.ReadFile(out data, fileHandle, readOffset, (int)client.MaxReadSize);
        
        if (status == NTStatus.STATUS_SUCCESS)
        {
            if (data == null || data.Length == 0) break;
            // 把读取到的字节写入内存流
            memoryStream.Write(data, 0, data.Length);
            readOffset += data.Length;
        }
        else if (status == NTStatus.STATUS_END_OF_FILE)
        {
            // 读到文件末尾,正常退出循环
            break;
        }
        else
        {
            // 处理其他读取错误
            throw new IOException($"读取文件失败,状态码:{status}");
        }
    }

    // 重置流指针到起始位置,准备上传S3
    memoryStream.Position = 0;

    // 上传到AWS S3的逻辑
    var s3Client = new AmazonS3Client();
    var transferUtility = new TransferUtility(s3Client);
    await transferUtility.UploadAsync(memoryStream, "你的S3桶名称", "上传后的文件名.pdf");
}
finally
{
    // 确保关闭文件句柄
    fileStore.CloseFile(fileHandle);
}

关键说明

  • 直接使用完整文件路径打开目标文件,避免多次打开目录覆盖句柄的问题。
  • STATUS_END_OF_FILE是正常的读取结束标记,不是错误,捕获后退出循环即可。
  • 用using语句自动管理所有可释放资源,防止内存泄漏。
  • 上传S3前必须重置MemoryStream的指针到起始位置,否则会从流的末尾开始读取,导致上传空内容。

内容的提问来源于stack exchange,提问作者NHARI Med

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 13:32:36