提问者:小点点

在C/C++中打开驻留在“/sys/”下的文件时出错


我无法读取/sys(准确地说,/sys/devices/lnxsystm:00/lnxsybus:00/pnp0a08:00/device:01/pnp0c09:00/pnp0c0a:00/power_supply/bat0/capacity)下的文件。我已经尝试使用C方法(fopenfread)和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++)中,问题都是无法打开文件。


共2个答案

匿名用户

M_PATH可能在末尾包含换行符(\n),因为fgets不会删除它。 用0字节覆盖末尾的第一个换行符。

查找文件名的方法相当难看,并且依赖于外部工具; 我建议直接在C++代码中搜索文件(可能使用std::filesystemAPI)

匿名用户

阅读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)感兴趣。

阅读一本优秀的操作系统教科书,你将会从中受益。

相关问题


MySQL Query : SELECT * FROM v9_ask_question WHERE 1=1 AND question regexp '(c|c++|中|打开|驻|留在|sys|文件|出错)' ORDER BY qid DESC LIMIT 20
MySQL Error : Got error 'repetition-operator operand invalid' from regexp
MySQL Errno : 1139
Message : Got error 'repetition-operator operand invalid' from regexp
Need Help?