777 lines
29 KiB
C#
777 lines
29 KiB
C#
|
using Hardware.Info;
|
|||
|
using NAudio.CoreAudioApi;
|
|||
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Diagnostics;
|
|||
|
using System.IO;
|
|||
|
using System.Linq;
|
|||
|
using System.Net.NetworkInformation;
|
|||
|
using System.Runtime.InteropServices;
|
|||
|
using System.Threading.Tasks;
|
|||
|
|
|||
|
namespace XiaoZhiSharp.Utils
|
|||
|
{
|
|||
|
/// <summary>
|
|||
|
/// 主程序类
|
|||
|
/// 提供用户界面和主循环
|
|||
|
/// </summary>
|
|||
|
public class SystemMonitorTest
|
|||
|
{
|
|||
|
private static void getVolume()
|
|||
|
{
|
|||
|
MMDeviceEnumerator enumerator = new MMDeviceEnumerator();
|
|||
|
|
|||
|
// 获取默认扬声器设备
|
|||
|
MMDevice defaultSpeaker = enumerator.GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia);
|
|||
|
float speakerVolume = defaultSpeaker.AudioEndpointVolume.MasterVolumeLevelScalar;
|
|||
|
|
|||
|
// 获取默认麦克风设备
|
|||
|
MMDevice defaultMicrophone = enumerator.GetDefaultAudioEndpoint(DataFlow.Capture, Role.Communications);
|
|||
|
float microphoneVolume = defaultMicrophone.AudioEndpointVolume.MasterVolumeLevelScalar;
|
|||
|
Console.WriteLine("扬声器音量:" + speakerVolume + "\n" + "麦克风音量:" + microphoneVolume);
|
|||
|
}
|
|||
|
|
|||
|
private static void HardwareInfoLib(bool test)
|
|||
|
{
|
|||
|
getVolume();
|
|||
|
|
|||
|
IHardwareInfo hardwareInfo = new Hardware.Info.HardwareInfo();
|
|||
|
|
|||
|
hardwareInfo.RefreshOperatingSystem();
|
|||
|
hardwareInfo.RefreshMemoryStatus();
|
|||
|
hardwareInfo.RefreshBatteryList();
|
|||
|
hardwareInfo.RefreshBIOSList();
|
|||
|
hardwareInfo.RefreshComputerSystemList();
|
|||
|
hardwareInfo.RefreshCPUList(includePercentProcessorTime: test);
|
|||
|
hardwareInfo.RefreshDriveList();
|
|||
|
hardwareInfo.RefreshKeyboardList();
|
|||
|
hardwareInfo.RefreshMemoryList();
|
|||
|
hardwareInfo.RefreshMonitorList();
|
|||
|
hardwareInfo.RefreshMotherboardList();
|
|||
|
hardwareInfo.RefreshMouseList();
|
|||
|
hardwareInfo.RefreshNetworkAdapterList(includeBytesPerSec: test, includeNetworkAdapterConfiguration: test);
|
|||
|
hardwareInfo.RefreshPrinterList();
|
|||
|
hardwareInfo.RefreshSoundDeviceList();
|
|||
|
hardwareInfo.RefreshVideoControllerList();
|
|||
|
|
|||
|
//hardwareInfo.RefreshAll();
|
|||
|
|
|||
|
Console.WriteLine(hardwareInfo.OperatingSystem);
|
|||
|
|
|||
|
Console.WriteLine(hardwareInfo.MemoryStatus);
|
|||
|
|
|||
|
foreach (var hardware in hardwareInfo.BatteryList)
|
|||
|
Console.WriteLine(hardware);
|
|||
|
|
|||
|
foreach (var hardware in hardwareInfo.BiosList)
|
|||
|
Console.WriteLine(hardware);
|
|||
|
|
|||
|
foreach (var hardware in hardwareInfo.ComputerSystemList)
|
|||
|
Console.WriteLine(hardware);
|
|||
|
|
|||
|
foreach (var cpu in hardwareInfo.CpuList)
|
|||
|
{
|
|||
|
Console.WriteLine(cpu);
|
|||
|
|
|||
|
foreach (var cpuCore in cpu.CpuCoreList)
|
|||
|
Console.WriteLine(cpuCore);
|
|||
|
}
|
|||
|
|
|||
|
foreach (var drive in hardwareInfo.DriveList)
|
|||
|
{
|
|||
|
Console.WriteLine(drive);
|
|||
|
|
|||
|
foreach (var partition in drive.PartitionList)
|
|||
|
{
|
|||
|
Console.WriteLine(partition);
|
|||
|
|
|||
|
foreach (var volume in partition.VolumeList)
|
|||
|
Console.WriteLine(volume);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
foreach (var hardware in hardwareInfo.KeyboardList)
|
|||
|
Console.WriteLine(hardware);
|
|||
|
|
|||
|
foreach (var hardware in hardwareInfo.MemoryList)
|
|||
|
Console.WriteLine(hardware);
|
|||
|
|
|||
|
if (hardwareInfo.MemoryList.Count > 0)
|
|||
|
{
|
|||
|
var memoryStatus = hardwareInfo.MemoryStatus;
|
|||
|
//memoryStatus.
|
|||
|
// 计算内存占用率
|
|||
|
double usagePercentage = ((double)memoryStatus.TotalPhysical - memoryStatus.AvailablePhysical) /
|
|||
|
memoryStatus.TotalPhysical * 100;
|
|||
|
|
|||
|
Console.WriteLine($"总物理内存: {FormatBytes(memoryStatus.TotalPhysical)}");
|
|||
|
Console.WriteLine($"可用内存: {FormatBytes(memoryStatus.AvailablePhysical)}");
|
|||
|
Console.WriteLine($"已用内存: {FormatBytes(memoryStatus.TotalPhysical - memoryStatus.AvailablePhysical)}");
|
|||
|
Console.WriteLine($"内存占用率: {usagePercentage:F2}%");
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Console.WriteLine("无法获取内存信息");
|
|||
|
}
|
|||
|
|
|||
|
foreach (var hardware in hardwareInfo.MonitorList)
|
|||
|
Console.WriteLine(hardware);
|
|||
|
|
|||
|
foreach (var hardware in hardwareInfo.MotherboardList)
|
|||
|
Console.WriteLine(hardware);
|
|||
|
|
|||
|
foreach (var hardware in hardwareInfo.MouseList)
|
|||
|
Console.WriteLine(hardware);
|
|||
|
|
|||
|
foreach (var hardware in hardwareInfo.NetworkAdapterList)
|
|||
|
Console.WriteLine(hardware);
|
|||
|
|
|||
|
foreach (var hardware in hardwareInfo.PrinterList)
|
|||
|
Console.WriteLine(hardware);
|
|||
|
|
|||
|
foreach (var hardware in hardwareInfo.SoundDeviceList)
|
|||
|
Console.WriteLine(hardware);
|
|||
|
|
|||
|
foreach (var hardware in hardwareInfo.VideoControllerList)
|
|||
|
Console.WriteLine(hardware);
|
|||
|
|
|||
|
foreach (var address in Hardware.Info.HardwareInfo.GetLocalIPv4Addresses(NetworkInterfaceType.Ethernet, OperationalStatus.Up))
|
|||
|
Console.WriteLine(address);
|
|||
|
|
|||
|
Console.WriteLine();
|
|||
|
|
|||
|
foreach (var address in Hardware.Info.HardwareInfo.GetLocalIPv4Addresses(NetworkInterfaceType.Wireless80211))
|
|||
|
Console.WriteLine(address);
|
|||
|
|
|||
|
Console.WriteLine();
|
|||
|
|
|||
|
foreach (var address in Hardware.Info.HardwareInfo.GetLocalIPv4Addresses(OperationalStatus.Up))
|
|||
|
Console.WriteLine(address);
|
|||
|
|
|||
|
Console.WriteLine();
|
|||
|
|
|||
|
foreach (var address in Hardware.Info.HardwareInfo.GetLocalIPv4Addresses())
|
|||
|
Console.WriteLine(address);
|
|||
|
|
|||
|
Console.ReadLine();
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 主入口点
|
|||
|
/// </summary>
|
|||
|
public static async Task RunTest(string[] args)
|
|||
|
{
|
|||
|
HardwareInfoLib(true);
|
|||
|
HardwareInfoLib(false);
|
|||
|
|
|||
|
Console.WriteLine("系统监控工具 - 按任意键退出");
|
|||
|
Console.WriteLine("==========================================");
|
|||
|
|
|||
|
// 创建系统监控器实例
|
|||
|
var monitor = new OSSystemMonitor();
|
|||
|
|
|||
|
// 主监控循环
|
|||
|
while (!Console.KeyAvailable)
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
// 异步获取系统信息
|
|||
|
var info = await monitor.GetSystemInfoAsync();
|
|||
|
|
|||
|
// 显示系统信息
|
|||
|
Console.WriteLine($"操作系统: {info.OSPlatform}");
|
|||
|
var cpuUsage = $"CPU使用率: {info.CpuUsage}-";
|
|||
|
if (cpuUsage.EndsWith("%%"))
|
|||
|
{
|
|||
|
|
|||
|
}
|
|||
|
Console.WriteLine(cpuUsage);
|
|||
|
Console.WriteLine($"内存使用: {FormatBytes((ulong)info.UsedMemory)} / {FormatBytes((ulong)info.TotalMemory)} ({info.MemoryUsage}%)");
|
|||
|
Console.WriteLine($"磁盘使用: {FormatBytes((ulong)info.UsedDiskSpace)} / {FormatBytes((ulong)info.TotalDiskSpace)} ({info.DiskUsage}%)");
|
|||
|
Console.WriteLine("==========================================");
|
|||
|
|
|||
|
// 等待2秒后更新
|
|||
|
await Task.Delay(500);
|
|||
|
|
|||
|
// 移动光标到开头,覆盖上次的输出
|
|||
|
if (Console.CursorTop >= 5)
|
|||
|
{
|
|||
|
Console.SetCursorPosition(0, Console.CursorTop - 5);
|
|||
|
}
|
|||
|
}
|
|||
|
catch (Exception ex)
|
|||
|
{
|
|||
|
// 显示错误信息并继续运行
|
|||
|
Console.WriteLine($"错误: {ex.Message}");
|
|||
|
await Task.Delay(500);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 格式化字节数为易读的字符串
|
|||
|
/// 自动选择合适的单位(B, KB, MB, GB, TB)
|
|||
|
/// </summary>
|
|||
|
/// <param name="bytes">字节数</param>
|
|||
|
/// <returns>格式化后的字符串</returns>
|
|||
|
private static string FormatBytes(ulong bytes)
|
|||
|
{
|
|||
|
if (bytes == 0) return "0 B";
|
|||
|
|
|||
|
string[] suffixes = { "B", "KB", "MB", "GB", "TB" };
|
|||
|
int counter = 0;
|
|||
|
decimal number = bytes;
|
|||
|
|
|||
|
// 循环除以1024,直到找到合适的单位
|
|||
|
while (Math.Round(number / 1024) >= 1 && counter < suffixes.Length - 1)
|
|||
|
{
|
|||
|
number /= 1024;
|
|||
|
counter++;
|
|||
|
}
|
|||
|
|
|||
|
// 返回格式化后的字符串(保留1位小数)
|
|||
|
return $"{number:n1} {suffixes[counter]}";
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 系统信息数据模型类
|
|||
|
/// 用于存储和传递CPU、内存、磁盘的使用信息
|
|||
|
/// </summary>
|
|||
|
public class OSSystemInfo
|
|||
|
{
|
|||
|
/// <summary>CPU使用率百分比</summary>
|
|||
|
public double CpuUsage { get; set; }
|
|||
|
|
|||
|
/// <summary>内存使用率百分比</summary>
|
|||
|
public double MemoryUsage { get; set; }
|
|||
|
|
|||
|
/// <summary>总物理内存大小(字节)</summary>
|
|||
|
public long TotalMemory { get; set; }
|
|||
|
|
|||
|
/// <summary>已使用内存大小(字节)</summary>
|
|||
|
public long UsedMemory { get; set; }
|
|||
|
|
|||
|
/// <summary>磁盘使用率百分比</summary>
|
|||
|
public double DiskUsage { get; set; }
|
|||
|
|
|||
|
/// <summary>总磁盘空间大小(字节)</summary>
|
|||
|
public long TotalDiskSpace { get; set; }
|
|||
|
|
|||
|
/// <summary>已使用磁盘空间大小(字节)</summary>
|
|||
|
public long UsedDiskSpace { get; set; }
|
|||
|
|
|||
|
/// <summary>可用磁盘空间大小(字节)</summary>
|
|||
|
public long AvailableDiskSpace { get; set; }
|
|||
|
|
|||
|
/// <summary>操作系统平台名称</summary>
|
|||
|
public string OSPlatform { get; set; } = "";
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 系统监控器类
|
|||
|
/// 提供跨平台的CPU、内存、磁盘使用率监控功能
|
|||
|
/// </summary>
|
|||
|
public class OSSystemMonitor
|
|||
|
{
|
|||
|
// 用于计算CPU使用率的时间戳和处理器时间
|
|||
|
private DateTime _lastCpuTime;
|
|||
|
private TimeSpan _lastTotalProcessorTime;
|
|||
|
private Process _process;
|
|||
|
|
|||
|
// 用于Linux系统CPU使用率计算的缓存值
|
|||
|
private ulong _lastTotalCpuTime = 0;
|
|||
|
private ulong _lastTotalIdle = 0;
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 构造函数,初始化监控器
|
|||
|
/// </summary>
|
|||
|
public OSSystemMonitor()
|
|||
|
{
|
|||
|
// 获取当前进程实例,用于计算进程相关的系统资源使用情况
|
|||
|
_process = Process.GetCurrentProcess();
|
|||
|
|
|||
|
// 初始化时间戳,用于后续计算CPU使用率
|
|||
|
_lastCpuTime = DateTime.Now;
|
|||
|
_lastTotalProcessorTime = _process.TotalProcessorTime;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 异步获取系统信息
|
|||
|
/// 同时获取CPU、内存、磁盘的使用信息
|
|||
|
/// </summary>
|
|||
|
/// <returns>包含系统信息的OSSystemInfo对象</returns>
|
|||
|
public async Task<OSSystemInfo> GetSystemInfoAsync()
|
|||
|
{
|
|||
|
var info = new OSSystemInfo
|
|||
|
{
|
|||
|
OSPlatform = GetOSPlatform()
|
|||
|
};
|
|||
|
|
|||
|
// 使用Task.WhenAll并行获取各项系统信息,提高效率
|
|||
|
await Task.WhenAll(
|
|||
|
Task.Run(() => info.CpuUsage = GetCpuUsage()),
|
|||
|
Task.Run(() => GetMemoryInfo(info)),
|
|||
|
Task.Run(() => GetDiskInfo(info))
|
|||
|
);
|
|||
|
|
|||
|
return info;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 获取CPU使用率
|
|||
|
/// 根据操作系统平台调用不同的实现
|
|||
|
/// </summary>
|
|||
|
/// <returns>CPU使用率百分比</returns>
|
|||
|
private double GetCpuUsage()
|
|||
|
{
|
|||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
|||
|
{
|
|||
|
return GetWindowsCpuUsage();
|
|||
|
}
|
|||
|
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ||
|
|||
|
RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
|||
|
{
|
|||
|
return GetLinuxCpuUsage();
|
|||
|
}
|
|||
|
|
|||
|
return 0; // 未知平台返回0
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Windows平台获取CPU使用率
|
|||
|
/// 使用PerformanceCounter性能计数器
|
|||
|
/// </summary>
|
|||
|
/// <returns>CPU使用率百分比</returns>
|
|||
|
private double GetWindowsCpuUsage()
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
// 创建性能计数器实例,监控总处理器时间
|
|||
|
using (var cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total"))
|
|||
|
{
|
|||
|
// 首次调用NextValue()初始化计数器,返回的值通常不准确
|
|||
|
cpuCounter.NextValue();
|
|||
|
|
|||
|
// 等待1秒让计数器收集足够的数据
|
|||
|
System.Threading.Thread.Sleep(1000);
|
|||
|
|
|||
|
// 第二次调用获取准确的CPU使用率
|
|||
|
return Math.Round(cpuCounter.NextValue(), 2);
|
|||
|
}
|
|||
|
}
|
|||
|
catch
|
|||
|
{
|
|||
|
// 如果性能计数器不可用,使用备用的计算方法
|
|||
|
return CalculateCpuUsage();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 备用的CPU使用率计算方法
|
|||
|
/// 通过计算进程的处理器时间变化来估算CPU使用率
|
|||
|
/// </summary>
|
|||
|
/// <returns>估算的CPU使用率百分比</returns>
|
|||
|
private double CalculateCpuUsage()
|
|||
|
{
|
|||
|
var currentTime = DateTime.Now;
|
|||
|
var currentTotalProcessorTime = _process.TotalProcessorTime;
|
|||
|
|
|||
|
// 计算时间间隔内使用的CPU时间(毫秒)
|
|||
|
var cpuUsedMs = (currentTotalProcessorTime - _lastTotalProcessorTime).TotalMilliseconds;
|
|||
|
|
|||
|
// 计算经过的总时间(毫秒)
|
|||
|
var totalMsPassed = (currentTime - _lastCpuTime).TotalMilliseconds;
|
|||
|
|
|||
|
// 更新上一次的时间戳
|
|||
|
_lastCpuTime = currentTime;
|
|||
|
_lastTotalProcessorTime = currentTotalProcessorTime;
|
|||
|
|
|||
|
// 避免除以零错误
|
|||
|
if (totalMsPassed == 0) return 0;
|
|||
|
|
|||
|
// 计算CPU使用率:使用的CPU时间 / (CPU核心数 * 总时间)
|
|||
|
var cpuUsageTotal = cpuUsedMs / (Environment.ProcessorCount * totalMsPassed);
|
|||
|
|
|||
|
// 转换为百分比并四舍五入到两位小数
|
|||
|
return Math.Round(cpuUsageTotal * 100, 2);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Linux平台获取CPU使用率
|
|||
|
/// 通过解析/proc/stat文件来计算
|
|||
|
/// </summary>
|
|||
|
/// <returns>CPU使用率百分比</returns>
|
|||
|
private double GetLinuxCpuUsage()
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
// 读取/proc/stat文件,包含CPU统计信息
|
|||
|
var lines = File.ReadAllLines("/proc/stat");
|
|||
|
|
|||
|
// 查找以"cpu "开头的行(总CPU统计)
|
|||
|
var cpuLine = lines.FirstOrDefault(l => l.StartsWith("cpu "));
|
|||
|
if (cpuLine == null) return 0;
|
|||
|
|
|||
|
// 分割字符串,移除空条目
|
|||
|
var values = cpuLine.Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
|||
|
if (values.Length < 8) return 0;
|
|||
|
|
|||
|
// 解析各个时间字段(单位:jiffies,通常为10ms)
|
|||
|
var user = ulong.Parse(values[1]); // 用户模式时间
|
|||
|
var nice = ulong.Parse(values[2]); // 低优先级用户模式时间
|
|||
|
var system = ulong.Parse(values[3]); // 系统模式时间
|
|||
|
var idle = ulong.Parse(values[4]); // 空闲时间
|
|||
|
var iowait = ulong.Parse(values[5]); // I/O等待时间
|
|||
|
var irq = ulong.Parse(values[6]); // 中断处理时间
|
|||
|
var softirq = ulong.Parse(values[7]); // 软中断处理时间
|
|||
|
|
|||
|
// 计算总CPU时间和总空闲时间
|
|||
|
var totalCpuTime = user + nice + system + idle + iowait + irq + softirq;
|
|||
|
var totalIdle = idle + iowait;
|
|||
|
|
|||
|
// 如果是第一次调用,初始化缓存值并等待1秒后重新计算
|
|||
|
if (_lastTotalCpuTime == 0)
|
|||
|
{
|
|||
|
_lastTotalCpuTime = totalCpuTime;
|
|||
|
_lastTotalIdle = totalIdle;
|
|||
|
System.Threading.Thread.Sleep(1000);
|
|||
|
return GetLinuxCpuUsage(); // 递归调用获取第二次读数
|
|||
|
}
|
|||
|
|
|||
|
// 计算两次读数之间的差值
|
|||
|
var totalCpuDiff = totalCpuTime - _lastTotalCpuTime;
|
|||
|
var totalIdleDiff = totalIdle - _lastTotalIdle;
|
|||
|
|
|||
|
// 更新缓存值
|
|||
|
_lastTotalCpuTime = totalCpuTime;
|
|||
|
_lastTotalIdle = totalIdle;
|
|||
|
|
|||
|
// 避免除以零错误
|
|||
|
if (totalCpuDiff == 0) return 0;
|
|||
|
|
|||
|
// 计算CPU使用率:(1 - 空闲时间比例) * 100
|
|||
|
var cpuUsage = (1.0 - (double)totalIdleDiff / totalCpuDiff) * 100;
|
|||
|
return Math.Round(cpuUsage, 2);
|
|||
|
}
|
|||
|
catch
|
|||
|
{
|
|||
|
// 如果读取/proc/stat失败,使用备用的计算方法
|
|||
|
return CalculateCpuUsage();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 获取内存信息并填充到OSSystemInfo对象
|
|||
|
/// 根据操作系统平台调用不同的实现
|
|||
|
/// </summary>
|
|||
|
/// <param name="info">要填充的OSSystemInfo对象</param>
|
|||
|
private void GetMemoryInfo(OSSystemInfo info)
|
|||
|
{
|
|||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
|||
|
{
|
|||
|
GetWindowsMemoryInfo(info);
|
|||
|
}
|
|||
|
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ||
|
|||
|
RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
|||
|
{
|
|||
|
GetLinuxMemoryInfo(info);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Windows平台获取内存信息
|
|||
|
/// 使用PerformanceCounter性能计数器
|
|||
|
/// </summary>
|
|||
|
/// <param name="info">要填充的OSSystemInfo对象</param>
|
|||
|
private void GetWindowsMemoryInfo(OSSystemInfo info)
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
// 使用性能计数器获取可用内存字节数
|
|||
|
using (var memCounter = new PerformanceCounter("Memory", "Available Bytes"))
|
|||
|
{
|
|||
|
var availableMemory = memCounter.NextValue();
|
|||
|
var totalMemory = GetTotalPhysicalMemory();
|
|||
|
|
|||
|
info.TotalMemory = totalMemory;
|
|||
|
info.UsedMemory = totalMemory - (long)availableMemory;
|
|||
|
|
|||
|
// 计算内存使用率百分比
|
|||
|
if (totalMemory > 0)
|
|||
|
{
|
|||
|
info.MemoryUsage = Math.Round((double)info.UsedMemory / totalMemory * 100, 2);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
info.MemoryUsage = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
catch
|
|||
|
{
|
|||
|
// 如果性能计数器不可用,使用Windows API备选方案
|
|||
|
GetWindowsMemoryInfoAlternative(info);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Windows平台备用的内存信息获取方法
|
|||
|
/// 使用Windows API GlobalMemoryStatusEx
|
|||
|
/// </summary>
|
|||
|
/// <param name="info">要填充的OSSystemInfo对象</param>
|
|||
|
private void GetWindowsMemoryInfoAlternative(OSSystemInfo info)
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
// 创建内存状态结构体
|
|||
|
var memoryStatus = new MEMORYSTATUSEX();
|
|||
|
memoryStatus.dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX));
|
|||
|
|
|||
|
// 调用Windows API获取内存状态
|
|||
|
if (GlobalMemoryStatusEx(ref memoryStatus))
|
|||
|
{
|
|||
|
info.TotalMemory = (long)memoryStatus.ullTotalPhys;
|
|||
|
info.UsedMemory = (long)(memoryStatus.ullTotalPhys - memoryStatus.ullAvailPhys);
|
|||
|
|
|||
|
// 计算内存使用率百分比
|
|||
|
if (info.TotalMemory > 0)
|
|||
|
{
|
|||
|
info.MemoryUsage = Math.Round((double)info.UsedMemory / info.TotalMemory * 100, 2);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
info.MemoryUsage = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
catch
|
|||
|
{
|
|||
|
// 如果所有方法都失败,使用进程工作集作为近似值
|
|||
|
info.TotalMemory = GetTotalPhysicalMemory();
|
|||
|
info.UsedMemory = Environment.WorkingSet;
|
|||
|
|
|||
|
if (info.TotalMemory > 0)
|
|||
|
{
|
|||
|
info.MemoryUsage = Math.Round((double)info.UsedMemory / info.TotalMemory * 100, 2);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
info.MemoryUsage = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Linux平台获取内存信息
|
|||
|
/// 通过解析/proc/meminfo文件
|
|||
|
/// </summary>
|
|||
|
/// <param name="info">要填充的OSSystemInfo对象</param>
|
|||
|
private void GetLinuxMemoryInfo(OSSystemInfo info)
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
// 读取/proc/meminfo文件,包含内存统计信息
|
|||
|
var lines = File.ReadAllLines("/proc/meminfo");
|
|||
|
var memInfo = new Dictionary<string, long>();
|
|||
|
|
|||
|
// 解析每行数据
|
|||
|
foreach (var line in lines)
|
|||
|
{
|
|||
|
var parts = line.Split(':', StringSplitOptions.RemoveEmptyEntries);
|
|||
|
if (parts.Length == 2)
|
|||
|
{
|
|||
|
var key = parts[0].Trim();
|
|||
|
var valueString = parts[1].Trim().Split(' ')[0];
|
|||
|
|
|||
|
// 转换值(文件中的单位是KB,转换为字节)
|
|||
|
if (long.TryParse(valueString, out long value))
|
|||
|
{
|
|||
|
memInfo[key] = value * 1024;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// 优先使用MemAvailable(更准确反映可用内存)
|
|||
|
if (memInfo.ContainsKey("MemTotal") && memInfo.ContainsKey("MemAvailable"))
|
|||
|
{
|
|||
|
info.TotalMemory = memInfo["MemTotal"];
|
|||
|
info.UsedMemory = memInfo["MemTotal"] - memInfo["MemAvailable"];
|
|||
|
|
|||
|
if (info.TotalMemory > 0)
|
|||
|
{
|
|||
|
info.MemoryUsage = Math.Round((double)info.UsedMemory / info.TotalMemory * 100, 2);
|
|||
|
}
|
|||
|
}
|
|||
|
else if (memInfo.ContainsKey("MemTotal") && memInfo.ContainsKey("MemFree"))
|
|||
|
{
|
|||
|
// 如果没有MemAvailable,使用MemFree作为近似值
|
|||
|
info.TotalMemory = memInfo["MemTotal"];
|
|||
|
info.UsedMemory = memInfo["MemTotal"] - memInfo["MemFree"];
|
|||
|
|
|||
|
if (info.TotalMemory > 0)
|
|||
|
{
|
|||
|
info.MemoryUsage = Math.Round((double)info.UsedMemory / info.TotalMemory * 100, 2);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
catch
|
|||
|
{
|
|||
|
// 发生错误时清零相关字段
|
|||
|
info.MemoryUsage = 0;
|
|||
|
info.TotalMemory = 0;
|
|||
|
info.UsedMemory = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 获取磁盘信息并填充到OSSystemInfo对象
|
|||
|
/// 自动识别系统盘(Windows)或根分区(Linux)
|
|||
|
/// </summary>
|
|||
|
/// <param name="info">要填充的OSSystemInfo对象</param>
|
|||
|
private void GetDiskInfo(OSSystemInfo info)
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
DriveInfo systemDrive;
|
|||
|
|
|||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
|||
|
{
|
|||
|
// Windows:选择系统目录所在的驱动器
|
|||
|
systemDrive = DriveInfo.GetDrives()
|
|||
|
.FirstOrDefault(d => d.IsReady &&
|
|||
|
d.Name.Equals(Path.GetPathRoot(Environment.SystemDirectory),
|
|||
|
StringComparison.OrdinalIgnoreCase));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// Linux/macOS:首先尝试找到根目录所在的驱动器
|
|||
|
systemDrive = DriveInfo.GetDrives()
|
|||
|
.FirstOrDefault(d => d.IsReady && d.RootDirectory.FullName == "/");
|
|||
|
|
|||
|
// 如果没找到根分区,选择第一个可用的固定驱动器
|
|||
|
systemDrive ??= DriveInfo.GetDrives()
|
|||
|
.FirstOrDefault(d => d.IsReady && d.DriveType == DriveType.Fixed);
|
|||
|
}
|
|||
|
|
|||
|
// 如果找到系统盘且就绪,读取磁盘信息
|
|||
|
if (systemDrive != null && systemDrive.IsReady)
|
|||
|
{
|
|||
|
info.TotalDiskSpace = systemDrive.TotalSize;
|
|||
|
info.AvailableDiskSpace = systemDrive.AvailableFreeSpace;
|
|||
|
info.UsedDiskSpace = systemDrive.TotalSize - systemDrive.AvailableFreeSpace;
|
|||
|
|
|||
|
// 计算磁盘使用率百分比
|
|||
|
if (systemDrive.TotalSize > 0)
|
|||
|
{
|
|||
|
info.DiskUsage = Math.Round((double)info.UsedDiskSpace / systemDrive.TotalSize * 100, 2);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
info.DiskUsage = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
catch
|
|||
|
{
|
|||
|
// 发生错误时清零相关字段
|
|||
|
info.DiskUsage = 0;
|
|||
|
info.TotalDiskSpace = 0;
|
|||
|
info.UsedDiskSpace = 0;
|
|||
|
info.AvailableDiskSpace = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 获取总物理内存大小
|
|||
|
/// 跨平台实现,支持Windows和Linux
|
|||
|
/// </summary>
|
|||
|
/// <returns>总物理内存字节数</returns>
|
|||
|
private long GetTotalPhysicalMemory()
|
|||
|
{
|
|||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
// Windows平台使用GlobalMemoryStatusEx API
|
|||
|
var memoryStatus = new MEMORYSTATUSEX();
|
|||
|
memoryStatus.dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX));
|
|||
|
|
|||
|
if (GlobalMemoryStatusEx(ref memoryStatus))
|
|||
|
{
|
|||
|
return (long)memoryStatus.ullTotalPhys;
|
|||
|
}
|
|||
|
}
|
|||
|
catch
|
|||
|
{
|
|||
|
// 忽略错误,返回0
|
|||
|
}
|
|||
|
}
|
|||
|
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ||
|
|||
|
RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
// Linux/macOS平台读取/proc/meminfo文件
|
|||
|
var lines = File.ReadAllLines("/proc/meminfo");
|
|||
|
var totalLine = lines.FirstOrDefault(l => l.StartsWith("MemTotal"));
|
|||
|
|
|||
|
if (totalLine != null)
|
|||
|
{
|
|||
|
var parts = totalLine.Split(':', StringSplitOptions.RemoveEmptyEntries);
|
|||
|
if (parts.Length == 2)
|
|||
|
{
|
|||
|
var valueString = parts[1].Trim().Split(' ')[0];
|
|||
|
if (long.TryParse(valueString, out long value))
|
|||
|
{
|
|||
|
return value * 1024; // 转换为字节
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
catch
|
|||
|
{
|
|||
|
// 忽略错误,返回0
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return 0; // 默认返回0
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 获取操作系统平台名称
|
|||
|
/// </summary>
|
|||
|
/// <returns>操作系统平台名称字符串</returns>
|
|||
|
private string GetOSPlatform()
|
|||
|
{
|
|||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
|||
|
return "Windows";
|
|||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
|||
|
return "Linux";
|
|||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
|||
|
return "macOS";
|
|||
|
return "Unknown";
|
|||
|
}
|
|||
|
|
|||
|
// Windows API 结构体,用于获取内存状态信息
|
|||
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
|||
|
private struct MEMORYSTATUSEX
|
|||
|
{
|
|||
|
public uint dwLength; // 结构体大小
|
|||
|
public uint dwMemoryLoad; // 内存使用率百分比
|
|||
|
public ulong ullTotalPhys; // 总物理内存
|
|||
|
public ulong ullAvailPhys; // 可用物理内存
|
|||
|
public ulong ullTotalPageFile; // 总页面文件大小
|
|||
|
public ulong ullAvailPageFile; // 可用页面文件大小
|
|||
|
public ulong ullTotalVirtual; // 总虚拟内存
|
|||
|
public ulong ullAvailVirtual; // 可用虚拟内存
|
|||
|
public ulong ullAvailExtendedVirtual; // 可用扩展虚拟内存
|
|||
|
}
|
|||
|
|
|||
|
// Windows API 函数导入,用于获取全局内存状态
|
|||
|
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
|||
|
[return: MarshalAs(UnmanagedType.Bool)]
|
|||
|
private static extern bool GlobalMemoryStatusEx(ref MEMORYSTATUSEX lpBuffer);
|
|||
|
}
|
|||
|
}
|