zoukankan      html  css  js  c++  java
  • Linux下文件I/O详解与DS18B20温度采集

    1. 文件I/O与标准I/O区别

    文件I/O:文件I/O称之为不带缓存的IO(unbuffered I/O),不带缓存指的是每个read和write都调用内核中的一个系统调用,也就是一般所说的低级I/O——操作系统提供的基本IO服务,与os绑定,特定于Linux或Unix平台。这些不带缓存的I/O函数不是ANSI C的组成部分,但是是P O S I X . 1和X P G 3的组成部分。

    标准I/O:标准I/O是ANSI C建立的一个标准I/O模型,是一个标准函数包和stdio.h头文件中的定义,具有一定的可移植性。标准I/O库处理很多细节。例如缓存分配,以优化长度执行I/O等。标准的I/O提供了三种类型的缓存。

    它们函数使用的区别如下:在这里插入图片描述
    这里不再过多讨论标准I/O,目前只以文件I/O作为讲解。

    大多数Unix文件I/O只需用到5个函数:open、read、write、lseek 和 close

    2. 文件描述符

    对于内核而言,所有打开文件都由文件描述符引用。文件描述符是一个非负整数。当打开
    一个现存文件或创建一个新文件时,内核向进程返回一个文件描述符。当读、写一个文件时,用o p e n或c r e a t返回的文件描述符标识该文件,将其作为参数传送给 r e a d或w r i t e。
    默认情况下,程序在开始运行时,系统会自动打开三个文件描述符,0是标准输入,1是标准输出,2是标准错误。POSIX标准要求每次打开文件时(含socket)必须使用当前进程 中最小可用的文件描述符号码,因此第一次打开的文件描述符一定是3。

    文件描述符 用途 POSIX文件描述符 标准I/O文件流
    0 标准输入 STDIN_FILENO stdin
    1 标准输出 STDOUT_FILENO stdout
    2 标准出错 STDERR_FILENO stderr

    3. open / creat函数

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    int open(const char *pathname, int oflag,  ...  /* mode_t m o d e */ ) ;
    int creat(const char *pathname, mode_t mode);
    
    //返回:若成功为文件描述符,若出错为- 1
    

    open()系统调用用来打开一个文件,并返回一个文件描述符(file description), 并且该文件描述符是当前进程最小、未使用的 文件描述符数值。

    参数:
    pathname: 要打开的文件、设备的路径;
    oflag: 由多个选项进行或运算构造oflag参数。
    必选:

    • O_RDONLY (只读)
    • O_WRONLY(只写)
    • O_RDWR(读写)

    可选:

    • O_APPEND 每次写时都追加到文件的尾端。
    • O_CREAT 文件不存在则创建它,使用该选项需要第三个参数mode
    • O_TRUNC 如果文件存在,而且为只写或读写成功打开,则将其长度截取为0;
    • O_NONBLOCK 如果path是一个FIFO、块设备、字符特殊文件则此选项为文件的本次打开和后续的I/O操作 设置非阻塞模式方式。
    • O_EXEC、O_SEARCH、O_CLOEXEC、O_NOCTTY…

    mode: oflag带O_CREAT选项时可以用来创建文件,这时必须带该参数用来指定创建文件的权限模式,如0666。 否则不需要。
    注意,以下此函数等价:

    /* 两者等价 */
    creat(pathname, mode);
    open(pathname, O_WRONLY | O_CREAT | O_TRUNC, mode)  
    

    在早期的U N I X版本中, o p e n的第二个参数只能是 0、 1或2。没有办法打开一
    个尚未存在的文件,因此需要另一个系统调用 c r e a t以创建新文件。现在, o p e n函
    数提供了选择项O _ C R E AT和O _ T R U N C,于是也就不再需要c r e a t函数了。

    c r e a t的一个不足之处是它以只写方式打开所创建的文件。在提供 o p e n的新版本之前,如果要创建一个临时文件,并要先写该文件,然后又读该文件,则必须先调用 c r e a t, c l o s e,然后再调用o p e n。现在则可用下列方式调用o p e n:

    open(pathname, O_RDWR | O_CREAT | O_TRUNC, mode)  
    

    4. close函数

    可用c l o s e函数关闭一个打开文件:

    #include <unistd.h>
    /* 关闭打开的文件
     * @return      成功返回0,出错返回-1 */
    int close(int fd);
    

    功能:指定相应的文件描述符就可以关闭打开的文件。
    参数:fd文件描述符,是open或者creat返回的非负整数。

    5. lseek函数

    每个打开文件都有一个与其相关联的“当前文件位移量”。它是一个非负整数,用以度量
    从文件开始处计算的字节数。 通常,读、写操作都从当前文件位移量处开始,并使位移量增加所读或写的字节数。按系统默认,当打开一个文件时,除非指定O _ A P P E N D选择项,否则该位移量被设置为0。
    可以调用l s e e k显式地定位一个打开文件。

    #include <sys/types.h>
    #include <unistd.h>
    off_t lseek(int filedes, off_to ffset, int whence) ;
    //返回:若成功为新的文件位移,若出错为- 1
    

    对参数offset 的解释与参数w h e n c e的值有关。

    • 若w h e n c e是S E E K _ S E T,则将该文件的位移量设置为距文件开始处 offset 个字节。
    • 若w h e n c e是S E E K _ C U R,则将该文件的位移量设置为其当前值加offset, offset可为正或负。
    • 若w h e n c e是S E E K _ E N D,则将该文件的位移量设置为文件长度加offset, offset可为正或负。

    普通文件的偏移量必须是非负整数。偏移量可以大于文件的长度,这样之后的写会形成一个空洞,空洞不占存储,其中的字节被读为0。

    6. read / write函数

    用r e a d函数从打开文件中读数据。

    #include <unistd.h>
    ssize_t read(int fd, void *buf, size_t count);
    //返回:读到的字节数,若已到文件尾为 0,若出错为- 1
    
    ssize_t write(int fd, const void *buf, size_t count);
    //返回:若成功为已写的字节数,若出错为- 1
    

    带符号整数( ssize_t);不带符号整数(size_t)。
    参数:
    fd:相应文件的文件描述符;
    buf:读/写的缓冲区;
    count:对read,为要读的字节数; 对write,为buf的大小。

    read有多种情况可使实际读到的字节数少于要求读字节数:

    • 读普通文件时,在读到要求字节数之前已到达了文件尾端。例如,若在到达文件尾端之前还有3 0个字节,而要求读1 0 0个字节,则r e a d返回3 0,下一次再调用r e a d时,它将返回0 (文件尾端);
    • 当从终端设备读时,通常一次最多读一行;
    • 当从网络读时,网络中的缓冲机构可能造成返回值小于所要求读的字节数;
    • 某些面向记录的设备,例如磁带,一次最多返回一个记录。

    7. DS18B20温度采集

    文件file_io.c如下:

    #include <stdio.h>
    #include <errno.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include "file_io.h"
    
    #define BUFSIZE 1024
    //#define MSG_STR "Hello World
    "
    
    int main(int argc, char *argv[])
    {
        int     fd = -1;
        int     rv = -1;
        char    buf[BUFSIZE];
        float   temper;  
    
        fd=open("test.txt", O_RDWR|O_CREAT|O_TRUNC, 0666);
        if(fd < 0)
        {
    
            perror("Open/Create file test.txt failure");
            return 0;
        }
        printf("Open file returned file descriptor [%d]
    ", fd);
         
        if((get_temper(&temper)) < 0)
        {
            printf("Get temperature failure: %s
    ", strerror(errno));
        	goto cleanup;
        }
    
        memset(buf, 0, sizeof(buf));
        snprintf(buf, sizeof(buf), "%.2f%c", temper, 'C');
    
        if( (rv=write(fd, buf, strlen(buf))) < 0 )
        {
            printf("Write %d bytes into file failure: %s
    ", rv, strerror(errno));
            goto cleanup;
        }
    
        lseek(fd, 0, SEEK_SET);
    
        memset(buf, 0, sizeof(buf));
        if( (rv=read(fd, buf, sizeof(buf))) < 0 )
        {
            printf("Read data from file failure: %s
    ", strerror(errno));
            goto cleanup;
        }
        
        printf("Read %d bytes data from file: %s
    ", rv, buf);
    
    cleanup:
        close(fd);
        return 0;
    
    }
    

    文件file_io.h如下:

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <dirent.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <syslog.h>
    #include <errno.h>
    
    /*  温度放置的路径 */
    //#define filepath /28-041731f7c0ff/w1_slave
    
    int get_temper(float *temper);
    
    int get_temper(float *temper)
    {
        char 	        filepath[120]="/";
        char	        f_name[50];
        char            data_array[1024];
        char            *data_p=NULL;
        struct dirent   *file=NULL;
        DIR             *dir=NULL;
        int             data_fd;
        int             found = -1;
        //float           *temper;
    
        if((dir = opendir(filepath)) < 0)
        {
            printf("opendir file failure: %s
    ",strerror(errno));
            return -1;
        }
    
        while((file = readdir(dir)) != NULL)
        {
            //if((strcmp(file->d_name, ".", 1) == 0) || (strcmp(file->d_name, ".", 1) == 0))
            //continue;               //ignore '.' and '..' file
            if(strstr(file->d_name, "28-")) 
            {   //memset(f_name, 0, sizeof(f_name));
                strncpy(f_name, file->d_name, sizeof(f_name));       //locate reserve temperature data file path
                found = 1;
                printf("reserve temperature data file path: %s
    ",f_name);
            }
            //closedir(dir);
        }
        closedir(dir);
        /* found == 0; 未找到目的文件夹 */
        if(!found) 
        {
            printf("Can not find the folder
    ");   
            return 0;
        }
        
        /* 找到相应文件夹后,切换至该文件夹下以获取温度数据 */
        strncat(filepath, f_name, sizeof(filepath)-strlen(filepath));       //将文件夹名连接到filepath路径后
        strncat(filepath, "/w1_slave", sizeof(filepath)-strlen(filepath));  //将设备文件夹下存放温度的文件连接到filepath路径后
        
        //printf("%s
    ", f_name);
        printf("%s
    ", filepath );
        data_fd=open(filepath, O_RDONLY);
        if(data_fd < 0) 
        {
            printf("open file failure: %s
    ", strerror(errno));
            return -2;
        }
        memset(data_array, 0, sizeof(data_array));
        if(read(data_fd, data_array, sizeof(data_array)) < 0)
        {
            printf("read file failure: %s
    ", strerror(errno));
            return -3;
        }
        /* data_p指针后移两个字符单位,其后即为温度数据 */
        data_p=strstr(data_array, "t=");
        data_p=data_p+2;        //local temperature data 
        *temper=atof(data_p)/1000;    //"()" priority super "/"
        
        close(data_fd);
    
        return 0;
    }
    

    这里是DS18B20温度的采集内容,这里我只取一次温度采集数据,然后分析出温度值。
    路径为:/28-041731f7c0ff
    文件w1_slave内容如下:

    fe 00 4b 46 7f ff 0c 10 56 : crc=56 YES
    fe 00 4b 46 7f ff 0c 10 56 t=15875
    

    其运行结果为:

  • 相关阅读:
    atitit.TokenService v3 qb1 token服务模块的设计 新特性.docx
    Atitit attilax在自然语言处理领域的成果
    Atitit 图像清晰度 模糊度 检测 识别 评价算法 原理
    Atitit (Sketch Filter)素描滤镜的实现  图像处理  attilax总结
    atitit。企业的价值观 员工第一 vs 客户第一.docx
    Atitit 实现java的linq 以及与stream api的比较
    Atitit dsl exer v3 qb3 新特性
    Atititi tesseract使用总结
    Atitit 修改密码的功能流程设计 attilax总结
    atitit.TokenService v3 qb1  token服务模块的设计 新特性.docx
  • 原文地址:https://www.cnblogs.com/Tavi/p/12514020.html
Copyright © 2011-2022 走看看