我无法读取/sys
(准确地说,/sys/devices/lnxsystm:00/lnxsybus:00/pnp0a08:00/device:01/pnp0c09:00/pnp0c0a:00/power_supply/bat0/capacity
)下的文件。我已经尝试使用C方法(fopen
和fread
)和C++方法(std::ifstream
)。以下是我目前所做的工作:
//headerfile.h
protected:
char m_path[150];
QString m_temp;
std::string m_temp_str;
FILE *m_pipePtr;
std::ifstream m_batPtr;
//Inside a member function definition :
...
m_pipePtr = popen("find /sys 2>/dev/null | grep \"BAT0/capacity\" | grep -v \"capacity_level\"" , "r");
if(m_pipePtr == NULL){
qDebug() << "Cannot read the battery percentage\n" << endl;
exit(1);
}
fgets(m_path , sizeof(m_path) , m_pipePtr);
...
m_batPtr.open(m_path);
qDebug() << m_path << endl; //Path is correct
m_batPtr >> m_temp_str;
std::cout << m_temp_str << std::endl; //Empty
m_temp = QString::fromStdString(m_temp_str);
qDebug() << m_temp << endl; //Empty too
return m_temp;
我可以cat
那个文件,它返回所需的结果。下面的程序也按预期工作(看起来很奇怪,但fread
在这里工作得很好,但在上面的文件中却不行):
#include <stdio.h>
#include <stdlib.h>
void main(){
FILE *fp2;
fp2 = fopen("/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:01/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/capacity" , "r");
char temp[4];
fread(temp , 3 , 1 , fp2);
printf("%s\n" , temp);
fclose(fp2);
}
那有什么不对?
编辑:以下内容的输出:
m_batPtr = fopen(m_path , "r");
std::cout << m_path << std::endl;
Q_ASSERT(m_batPtr);
是:
/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:01/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/capacity
ASSERT: "m_batPtr" in file ../batpercindicator/batperc.cpp, line 18
Aborted (core dumped)
在两种场景(C和C++)中,问题都是无法打开文件。
M_PATH
可能在末尾包含换行符(\n
),因为fgets
不会删除它。 用0字节覆盖末尾的第一个换行符。
查找文件名的方法相当难看,并且依赖于外部工具; 我建议直接在C++代码中搜索文件(可能使用std::filesystem
API)
阅读fopen(3)的文档。 失败是可能的。
最好在find(1)上使用nftw(3)而不是popen(3)。 更安全,更快。 参见path_resolution(7)
当该函数失败时,它设置errno(3),然后您可以使用perror(3)
所以您至少应该编写以下代码:
FILE *fp2 = fopen("/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00"
"/device:01/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/capacity" ,
"r");
if (!fp2) {
perror("failed to get battery capacity");
exit(EXIT_FAILURE);
};
如果您得到没有这样的文件或目录
,您就知道失败的原因了。
您可能需要阅读有关systemd的更多信息。
还可以使用一些终端仿真程序来运行shell命令,例如
/bin/ls -l /sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:01/PNP0C09:00/PNP0C0A:00/power_supply/BAT0/capacity
与您的程序并行。
花几天时间阅读Advanced Linux Programming,然后阅读syscalls(2)。 您应该对在其他终端模拟器中使用GDB和GCC以及strace(1)感兴趣。
阅读一本优秀的操作系统教科书,你将会从中受益。