使用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
解决方案
代码问题点
- 重复覆盖文件句柄:前两次调用
CreateFile打开目录,直接覆盖了directoryHandle变量,完全没必要,直接用完整文件路径打开目标文件即可。 - 未处理文件末尾状态:
STATUS_END_OF_FILE是读取到文件末尾的正常标记,不是错误,需要捕获并退出循环。 - 未写入读取数据:读取到有效数据后没写入
MemoryStream,导致最终流为空。 - 资源未释放: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
相关产品推荐
相关产品推荐

