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

.NET中如何识别Linux文件类型(常规文件、目录、符号链接等)

Linux文件类型判断的.NET托管实现方案

.NET 5及以上版本已经提供原生托管API支持Linux文件类型判断,不需要调用外部bash进程,低版本.NET也可以通过P/Invoke调用libc接口实现,以下是具体实现方式:

核心判断逻辑

.NET 在System.IO命名空间下提供了File.GetUnixFileMode(string path)方法,可直接读取Unix系系统的文件类型与权限标识位,该API返回的UnixFileMode枚举已经包含7种Linux文件类型的对应掩码:

  • UnixFileMode.Regular:常规文件(对应标识-)
  • UnixFileMode.Directory:目录(对应标识d)
  • UnixFileMode.CharacterDevice:字符设备文件(对应标识c)
  • UnixFileMode.BlockDevice:块设备文件(对应标识b)
  • UnixFileMode.Socket:本地套接字文件(对应标识s)
  • UnixFileMode.NamedPipe:命名管道(对应标识p)
  • UnixFileMode.SymbolicLink:符号链接(对应标识l)

常规文件判断示例

你需要的「仅当路径存在且为常规文件返回真值」的逻辑可以这么实现:

using System.IO;

public static bool IsRegularFile(string path)
{
    // 先过滤不存在的路径
    if (!File.Exists(path))
        return false;
    try
    {
        var mode = File.GetUnixFileMode(path);
        // 按位与提取文件类型位,匹配常规文件标识
        return (mode & UnixFileMode.TypeMask) == UnixFileMode.Regular;
    }
    catch (IOException)
    {
        // 无访问权限、文件被占用等异常场景返回false
        return false;
    }
    catch (PlatformNotSupportedException)
    {
        // Windows平台兼容逻辑,File.Exists默认仅对常规文件返回true
        return File.Exists(path);
    }
}

注意:File.GetUnixFileMode默认会跟随符号链接,如果你需要判断路径本身是否为符号链接而非指向的目标类型,可以使用FileInfo.LinkTarget属性判断,或者打开文件句柄时指定O_NOFOLLOW参数避免跟随符号链接。

通用文件类型判断封装

可以封装通用方法返回对应文件类型:

public enum UnixFileType
{
    Regular,
    Directory,
    CharacterDevice,
    BlockDevice,
    Socket,
    NamedPipe,
    SymbolicLink,
    Unknown
}

public static UnixFileType GetUnixFileType(string path)
{
    if (!File.Exists(path) && !Directory.Exists(path))
        return UnixFileType.Unknown;
    try
    {
        var mode = File.GetUnixFileMode(path);
        var typeFlag = mode & UnixFileMode.TypeMask;
        return typeFlag switch
        {
            UnixFileMode.Regular => UnixFileType.Regular,
            UnixFileMode.Directory => UnixFileType.Directory,
            UnixFileMode.CharacterDevice => UnixFileType.CharacterDevice,
            UnixFileMode.BlockDevice => UnixFileType.BlockDevice,
            UnixFileMode.Socket => UnixFileType.Socket,
            UnixFileMode.NamedPipe => UnixFileType.NamedPipe,
            UnixFileMode.SymbolicLink => UnixFileType.SymbolicLink,
            _ => UnixFileType.Unknown
        };
    }
    catch
    {
        return UnixFileType.Unknown;
    }
}

低于.NET 5版本的兼容方案

如果使用的是.NET Core 3.1及更早版本,没有内置的GetUnixFileModeAPI,可以通过P/Invoke调用libc的stat函数实现,也是纯托管实现不需要调用外部进程:

using System.Runtime.InteropServices;

// 适配x64架构Linux的stat结构体定义,其他架构需要对应调整字段顺序和长度
[StructLayout(LayoutKind.Sequential)]
private struct StatBuf
{
    public ulong st_dev;
    public ulong st_ino;
    public ulong st_nlink;
    public uint st_mode;
    public uint st_uid;
    public uint st_gid;
    public ulong st_rdev;
    public long st_size;
    public long st_blksize;
    public long st_blocks;
    public long st_atime;
    public long st_atime_nsec;
    public long st_mtime;
    public long st_mtime_nsec;
    public long st_ctime;
    public long st_ctime_nsec;
}

[DllImport("libc", SetLastError = true)]
private static extern int stat(string path, out StatBuf buf);

// Linux sys/stat.h中定义的文件类型掩码和标识
private const uint S_IFMT = 0xF000;
private const uint S_IFREG = 0x8000; // 常规文件
private const uint S_IFDIR = 0x4000; // 目录
private const uint S_IFCHR = 0x2000; // 字符设备
private const uint S_IFBLK = 0x6000; // 块设备
private const uint S_IFIFO = 0x1000; // 命名管道
private const uint S_IFLNK = 0xA000; // 符号链接
private const uint S_IFSOCK = 0xC000; // 套接字

public static bool IsRegularFileLegacy(string path)
{
    if (!File.Exists(path))
        return false;
    var buf = new StatBuf();
    if (stat(path, out buf) != 0)
        return false;
    return (buf.st_mode & S_IFMT) == S_IFREG;
}

内容的提问来源于stack exchange,提问作者Maxim V. Pavlov

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 17:06:04