用udevadm info -q path -n /dev/xxx查出/devices/路径,再替换为/sys/devices/即得sysfs路径;读取时须用open+read一次性读完并手动加\0,避免fopen/fread截断;权限问题应配udev规则而非chmod。

sysfs路径怎么找:别硬猜,用udevadm查
/sys 下的设备目录不是固定不变的,不同内核版本、驱动加载顺序都可能改变路径。硬编码 /sys/class/hwmon/hwmon0/temp1_input 这类路径在另一台机器上大概率失效。
用 udevadm 定位真实路径最可靠:
udevadm info -q path -n /dev/hidraw0 # 输出类似:/devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/0003:046D:C52B.0001/hidraw/hidraw0再把
/devices/ 替换成 /sys/devices/,就能拼出 sysfs 对应路径。对温度传感器这类通用设备,优先查 /sys/class/hwmon/ 下每个子目录里的 name 文件内容,匹配设备型号。
读取文件要用 open + read,别用 fopen
sysfs 中的属性文件(如 temp1_input)是内核通过 seq_file 机制生成的,不支持 fseek 或多次 fread。用 C 标准库的 fopen/fread 可能读到空或截断数据,尤其在多线程反复读取时。
正确做法是:
- 用
open()以O_RDONLY打开 - 用
read()一次性读完(注意缓冲区大小,通常 64 字节足够) - 手动加
\0终止符,再用strtol解析数字
int fd = open("/sys/class/hwmon/hwmon0/temp1_input", O_RDONLY);
char buf[64];
ssize_t n = read(fd, buf, sizeof(buf)-1);
if (n > 0) {
buf[n] = '\0';
long temp = strtol(buf, nullptr, 10); // 单位是毫摄氏度
}
close(fd);
权限不足时不要 chmod,改用 udev 规则
普通用户直接读 /sys/class/power_supply/BAT0/capacity 常见报错:Permission denied。临时 chmod 644 不仅无效(sysfs 权限由内核控制),还可能被下次内核模块重载重置。
长期方案是写 udev 规则:
# /etc/udev/rules.d/99-sysfs-power.rules SUBSYSTEM=="power_supply", MODE="0444" SUBSYSTEM=="hwmon", MODE="0444"然后运行
sudo udevadm control --reload-rules && sudo udevadm trigger。规则中用 MODE="0444" 而非 0644,避免意外写入导致内核报错。
读取频率别太高,小心触发内核限流
某些 sysfs 接口(如 USB 设备的 device/descriptor 或 NVMe 的 queue/0/requests)在高频率读取时会被内核限流,连续读可能返回旧值或 EAGAIN。实测在 10ms 内重复读同一文件,部分硬件驱动会静默降频。
建议:
- 温度/电压类状态每 1–2 秒读一次足矣
- 若需高频监控(如风扇转速),优先查
/proc/sys/dev/下对应接口,或用inotify监听文件变更而非轮询 - 读失败时不要死循环重试,sleep 至少 100ms 再试
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











