using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.InteropServices; namespace dy.net.utils { public static class DiskInfoHelper {/// /// 在Docker容器中获取Linux宿主机的本地固定磁盘总空间(GB) /// 前提:宿主机需挂载 /proc 到容器内的 /host/proc(启动时加 -v /proc:/host/proc:ro) /// /// 总空间字符串(如 "1408.35 GB"),失败时返回错误信息 public static string GetDockerHostTotalDiskSpaceGB() { try { // 1. 检查是否为Linux宿主机(Docker主要运行在Linux上) if (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { return "仅支持Linux宿主机(Docker容器内)"; } // 2. 检查宿主机/proc是否已挂载到容器 string hostProcMountsPath = "/app/db/mounts"; if (!File.Exists(hostProcMountsPath)) { return "未检测到宿主机/proc挂载,请使用 -v /proc:/host/proc:ro 启动容器"; } // 3. 从宿主机/proc/mounts筛选物理磁盘挂载点(排除虚拟文件系统) var physicalMounts = GetHostPhysicalMounts(hostProcMountsPath); if (!physicalMounts.Any()) { return "未找到宿主机的物理磁盘挂载点"; } // 4. 计算所有物理磁盘的总空间(通过df命令获取挂载点的总空间) long totalBytes = 0; foreach (var mountPoint in physicalMounts) { // 执行df命令获取宿主机挂载点的总空间(需容器内有df工具,或通过/proc/diskstats计算) var (success, bytes) = GetMountPointTotalBytes(mountPoint); if (success) { totalBytes += bytes; } } if (totalBytes == 0) { return "无法读取宿主机磁盘空间(可能权限不足)"; } // 5. 转换为GB return ConvertBytesToGb(totalBytes); } catch (Exception ex) { return $"获取宿主机磁盘空间失败:{ex.Message}"; } } /// /// 从宿主机/proc/mounts筛选物理磁盘挂载点(排除虚拟文件系统) /// private static List GetHostPhysicalMounts(string hostProcMountsPath) { var physicalMounts = new List(); // 虚拟文件系统类型(排除这些类型,剩下的视为物理磁盘相关) var virtualFsTypes = new HashSet { "tmpfs", "sysfs", "proc", "devtmpfs", "devpts", "cgroup", "cgroup2", "securityfs", "pstore", "debugfs", "hugetlbfs", "mqueue", "configfs", "fusectl", "overlay", "squashfs", "overlay2" // overlay/overlay2是Docker自身的存储驱动,需排除 }; foreach (var line in File.ReadAllLines(hostProcMountsPath)) { var parts = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (parts.Length >= 3) { string device = parts[0]; // 设备名(如/dev/sda1) string mountPoint = parts[1]; // 挂载点(如/) string fsType = parts[2]; // 文件系统类型 // 筛选条件:非虚拟文件系统 + 设备名以/dev/开头(物理设备) if (!virtualFsTypes.Contains(fsType) && device.StartsWith("/dev/")) { physicalMounts.Add(mountPoint); } } } return physicalMounts.Distinct().ToList(); } /// /// 通过df命令获取宿主机挂载点的总空间(字节) /// (需容器内安装coreutils,或替换为解析/proc/diskstats的逻辑) /// private static (bool success, long totalBytes) GetMountPointTotalBytes(string hostMountPoint) { try { // 在容器内执行df命令,指定宿主机的挂载点(需宿主机路径在容器内可见,或通过/proc计算) // 注意:df命令返回的是1K-blocks,需转换为字节(*1024) var process = new System.Diagnostics.Process { StartInfo = new System.Diagnostics.ProcessStartInfo { FileName = "df", Arguments = $"-P {hostMountPoint}", // -P 确保输出格式一致 RedirectStandardOutput = true, UseShellExecute = false, CreateNoWindow = true } }; process.Start(); string output = process.StandardOutput.ReadToEnd(); process.WaitForExit(); if (process.ExitCode != 0) { return (false, 0); } // 解析df输出(第二行为数据行) var lines = output.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); if (lines.Length < 2) { return (false, 0); } var dataParts = lines[1].Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (dataParts.Length >= 2 && long.TryParse(dataParts[1], out long blocks)) { return (true, blocks * 1024); // 1K-blocks -> 字节 } return (false, 0); } catch { return (false, 0); } } /// /// 字节转GB(1GB = 1024^3字节) /// private static string ConvertBytesToGb(long bytes) { if (bytes <= 0) return "磁盘空间计算错误"; double gb = (double)bytes / (1024 * 1024 * 1024); return $"{gb:F2} GB"; } } }