#Raspbian C应用编程#Linux 文件I/O – 系统温度主频记录器

/ 1评 / 0

成果的两份工程:
file_wr
cpu_temp_logger
UNIX/Linux 的一个基本哲学是"一切皆文件".不仅普通的文件,甚至连各种字符设备、 块设备、套接字等都被当成文件对待,尽管它们的类型差异很大,但 UNIX/Linux 为它们提 供的操作界面却是相同的. Linux 把大部分系统资源当作文件并呈现给用户,用户只需按照文件 I/O 的方式,就能完成数据的输入输出. Linux 文件按其代表的具体对象,可大致分类为:

  1. 普通文件,即一般意义上的文件、磁盘文件;
  2. 设备文件,代表的是系统中一个具体的设备;
  3. 管道文件、 FIFO 文件,一种特殊文件,常用于进程间通信;
  4. 套接字( socket)文件,主要用在网络通信方面.

文件 I/O 的常用操作方法有"打开"、"关闭"、"读"和"写"等.只要是文件,所有文件都有前面两种方法.系统提供了文件 I/O API,以函数的形式提供给应用程序调用.打开文件对应的函数是 open(),读文件对应的函数是 read(),写文件对应的函数是 write(),关闭文件对应的函数是 close()
文件描述符 是进程中用来表示某个文件的一个变量, 文件描述符的作用,类似于在排队取号,业务员(进程)通过叫号(文件描述符)就能找到来搞事的人(文件)

大多数 Raspbian系统中,可通过命令"ulimit -n"查询到这个数值的大小,但注意,不是所有Linux都有这个指令.

文件描述符 012 在Linux上有特殊意义,我们暂时可以不去理解他.只知道他们比较特殊就行了,所以实际上树莓派只有最多7312个同时打开文件.(难道还不够?)
另外文件操作要涉及几个头文件,死记硬背.要用到哪个函数,就用哪个头文件,就是这样的.

#include<sys/types.h> /* 定义数据类型,如 ssize_t, off_t 等 */
#include <fcntl.h> /* 定义 open, creat 等函数原型,创建文件权限的符号常量 S_IRUSR 等 */
#include <unistd.h> /* 定义 read, write, close, lseek 等函数原型 */
#include <errno.h> /* 与全局变量 errno 相关的定义 */
#include <sys/ioctl.h> /* 定义 ioctl 函数原型 */

我们这就上Pi实践下,还是使用VS + Visual GDB神奇组合.就算你不懂Linux各种繁琐指令也能写出不错的程序.如果还不是特别了解,就参考下之前的文章吧.
下面演示的例子,先以可写方式打开当前目录下的hello.txt文件,如果该文件不存在,则创建文件,再往文件中写入一个字符串Hello, welcome to 52pi.net!,把操作结果输出到终端后,关闭文件. 接着再次以只读模式打开该文件,读取刚才写入的数据,并把结果输出到终端最后关闭该文件.
代码:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
int main(int argc, char *argv [])
{
	char sz_str [] = "Hello, welcome to 52pi.net!";
	char sz_filename [] = "hello.txt";
	int fd = -1;
	int res = 0;
	char buf[128] = {0x00};
	fd = open(sz_filename, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
	if (fd < 0)
	{
		printf("Open file %s failed,errno = %d.
", sz_filename, errno);
		return -1;
	}
	res = write(fd, sz_str, sizeof(sz_str));
	printf("write %d bytes to %s 
", res, sz_filename);
	fsync(fd);
	close(fd);
	fd = open(sz_filename, O_RDONLY);
	if (fd < 0)
	{
		printf("Open file %s failed,errno = %d.
", sz_filename, errno);
		return -1;
	}
	res = read(fd, buf, sizeof(buf));
	buf[res] = '';
	printf("read %d bytes from file %s ,data = %s 
", res, sz_filename, buf);
	close(fd);
	return 0;
}

测试结果:

那么刚才代码里面的O_WRONLY都是什么定义呢,我们可以右键,转到定义去查看一下.

当然也可以看我解释:

而第二项权限意思是这样的:

如果不指定,权限就是000了,000代表谁都对这个文件没办法.
从上述我们已经了解到文件基本读写,那么现在开始实践,已知Raspbian系统的核心0的主频是存在/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq文件,而CPU温度是存在于/sys/class/thermal/thermal_zone0/temp文件.我们读取这两个文件,定时写入到一个文件里面做记录.
所以,记录工程应该长这个样子.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#include <time.h>
int main(int argc, char *argv [])
{
	int cpu_freq_fd = -1;
	int cpu_temp_fd = -1;
	int cpu_logger_fd = -1;
	char freq_buf[128] = {0x00};
	char temp_buf[128] = {0x00};
	char log_buf[1024] = {0x00};
	time_t rawtime;
	struct tm * timeinfo;
	cpu_freq_fd = open("/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq", O_RDONLY);
	cpu_temp_fd = open("/sys/class/thermal/thermal_zone0/temp", O_RDONLY);
	cpu_logger_fd = open("cpu.log", O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
	while (1)
	{
		lseek(cpu_freq_fd, 0, SEEK_SET); /* 回到文件的开始 */
		read(cpu_freq_fd, freq_buf, sizeof(freq_buf)); /* 读取文件 */
		lseek(cpu_temp_fd, 0, SEEK_SET);
		read(cpu_temp_fd, temp_buf, sizeof(temp_buf));
		time(&rawtime);
		timeinfo = localtime(&rawtime);
		char *now_time = asctime(timeinfo);
		now_time[strlen(now_time) - 1] = 0;
		sprintf(log_buf,"%s - CPU = %d MHz - Temp = %d degC
", now_time, atoi(freq_buf) / 1000, atoi(temp_buf) / 1000);
		write(cpu_logger_fd, log_buf, sizeof(log_buf));
		fsync(cpu_logger_fd);
		sleep(1);
	}
	close(cpu_freq_fd);
	close(cpu_temp_fd);
	close(cpu_logger_fd);
	return 0;
}

执行效果,是不是很棒,这样就有一个监控程序了.通过程序不难看出,就是不断写cpu.log文件.然后休眠.

  1. edeveloper说道:

    这个不错,可以记录更多东西就好了。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注