Files
douyin/utils/DiskInfoHelper.cs
T
2025-10-22 22:22:49 +08:00

164 lines
6.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
namespace dy.net.utils
{
public static class DiskInfoHelper
{/// <summary>
/// 在Docker容器中获取Linux宿主机的本地固定磁盘总空间(GB)
/// 前提:宿主机需挂载 /proc 到容器内的 /host/proc(启动时加 -v /proc:/host/proc:ro
/// </summary>
/// <returns>总空间字符串(如 "1408.35 GB"),失败时返回错误信息</returns>
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}";
}
}
/// <summary>
/// 从宿主机/proc/mounts筛选物理磁盘挂载点(排除虚拟文件系统)
/// </summary>
private static List<string> GetHostPhysicalMounts(string hostProcMountsPath)
{
var physicalMounts = new List<string>();
// 虚拟文件系统类型(排除这些类型,剩下的视为物理磁盘相关)
var virtualFsTypes = new HashSet<string>
{
"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();
}
/// <summary>
/// 通过df命令获取宿主机挂载点的总空间(字节)
/// (需容器内安装coreutils,或替换为解析/proc/diskstats的逻辑)
/// </summary>
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);
}
}
/// <summary>
/// 字节转GB1GB = 1024^3字节)
/// </summary>
private static string ConvertBytesToGb(long bytes)
{
if (bytes <= 0) return "磁盘空间计算错误";
double gb = (double)bytes / (1024 * 1024 * 1024);
return $"{gb:F2} GB";
}
}
}