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
    

    其运行结果为:

  • 相关阅读:
    易耗品管理 第三四表 查询的存储过程
    [zz]使用vc编译libsvm
    程序调试小bug
    Ubuntu下安装配置OpenNI, OpenCV
    关于Linux下使用OpenCv读取视频打不开的问题
    jQuery实现图片点击放大
    关于 QtDBus 的种种
    javascript计时器的实现
    [QT]没有选择Debug构建方式.为文件的某行设置断点可能会失败
    linux firefox 不显示英文的解决
  • 原文地址:https://www.cnblogs.com/Tavi/p/12514020.html
Copyright © 2011-2022 走看看