You need to enable JavaScript to run this app. C#调用GetFiles读取192.168.1.209共享目录时报系统调用级别不正确错误
优惠活动
大模型
产品
解决方案
定价
更多

C#调用GetFiles读取192.168.1.209共享目录时报系统调用级别不正确错误

报错原因定位
  • 报错和网络连通性、基础权限无关:资源管理器能直接浏览路径下的txt文件,本身就证明SMB连通、文件读取权限是正常的。
  • 两个特殊表现的核心指向是目标192.168.1.209的SMB共享存在兼容性缺陷:没有按Windows规范返回目录的扩展元数据(文件夹总容量、NTFS权限、创建时间戳)。
  • .NET 原生的DirectoryInfo.GetFiles() 方法在执行枚举时,会同步向SMB服务端请求目录完整元数据,服务端返回非标准响应时,内核层就会直接抛出“The system call level is not correct”的Win32异常。
  • 资源管理器能正常列文件,是因为它走轻量化枚举逻辑,不会强制拉取目录元数据;只有右键查看文件夹属性时才会触发元数据请求,所以会出现属性页加载失败的现象,和异常表现完全匹配。
可落地解决方案

服务端配置修正(根源解决)

  • 登录192.168.1.209设备,检查对应共享的权限配置:
    • 确认访问账号的共享权限勾选“读取及列出文件夹内容”,不能只勾选“读取”遗漏“列出文件夹目录”的特殊权限项
    • 检查共享文件夹所在NTFS分区的权限,确认账号拥有对文件夹本身的“列出文件夹/读取数据”权限,权限缺失会导致SMB返回的目录元数据不完整
  • 检查设备SMB服务配置:如果是第三方SMB实现(NAS、嵌入式设备、非Windows Server自带的SMB服务),确认协议版本设置,关闭SMB1兼容模式,切换到SMB2.0以上的标准协议模式——SMB1模式下的非标准实现经常出现元数据返回残缺的问题。

客户端替代枚举方案(无需修改服务端配置)

如果服务端配置无法调整,直接替换原生IO类的枚举逻辑,用Win32轻量化文件枚举接口实现文件扫描——这就是资源管理器列文件用的底层API,不会强制请求目录扩展元数据,哪怕服务端返回残缺元数据也能正常拿到文件列表。
替换后的代码实现如下:

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.IO;

public class NetworkShareReader
{
    // 引入Win32文件枚举接口
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool FindNextFile(IntPtr hFindFile, out WIN32_FIND_DATA lpFindFileData);

    [DllImport("kernel32.dll")]
    private static extern bool FindClose(IntPtr hFindFile);

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    private struct WIN32_FIND_DATA
    {
        public uint dwFileAttributes;
        public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime;
        public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime;
        public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime;
        public uint nFileSizeHigh;
        public uint nFileSizeLow;
        public uint dwReserved0;
        public uint dwReserved1;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
        public string cFileName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
        public string cAlternateFileName;
    }

    /// <summary>
    /// 轻量化枚举共享路径下的txt文件,兼容元数据返回不完整的共享
    /// </summary>
    /// <param name="sharePath">目标共享路径</param>
    /// <returns>txt文件名称列表</returns>
    public List<string> EnumerateTxtFiles(string sharePath)
    {
        List<string> txtFileList = new List<string>();
        string searchTarget = Path.Combine(sharePath, "*.txt");

        IntPtr searchHandle = FindFirstFile(searchTarget, out WIN32_FIND_DATA findData);
        if (searchHandle == (IntPtr)(-1))
        {
            int errorCode = Marshal.GetLastWin32Error();
            throw new IOException($"共享路径枚举失败,Win32错误码:{errorCode}");
        }

        try
        {
            do
            {
                // 跳过子目录项,仅匹配文件类型
                bool isDirectory = (findData.dwFileAttributes & (uint)FileAttributes.Directory) != 0;
                if (!isDirectory)
                {
                    txtFileList.Add(findData.cFileName);
                }
            } while (FindNextFile(searchHandle, out findData));
        }
        finally
        {
            FindClose(searchHandle);
        }

        return txtFileList;
    }
}

原来的业务逻辑只需要将原本的d.GetFiles("*.txt") 调用替换为上述类的EnumerateTxtFiles 方法即可,不需要额外的系统权限申请。

临时验证方案

如果暂时不需要修改代码,可以通过命令行将共享路径映射为本地网络驱动器,绕过原生DirectoryInfo的元数据预请求逻辑:

net use Z: \\192.168.1.209\user\HST /user:共享账号 共享密码

映射完成后,代码中直接读取Z:\ 路径下的txt文件即可,多数情况下内核会自动补全缺失的元数据请求,能临时解决报错问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.03 07:36:04