【北京迅为】《STM32MP157开发板嵌入式开发指南》- 第三十章 文件IO和标准IO

iTOP-STM32MP157开发板采用ST推出的双核cortex-A7+单核cortex-M4异构处理器,既可用Linux、又可以用于STM32单片机开发。开发板采用核心板+底板结构,主频650M、1G内存、8G存储,核心板采用工业级板对板连接器,高可靠,牢固耐用,可满足高速信号环境下使用。共240PIN,CPU功能全部引出:底板扩展接口丰富底板板载4G接口(选配)、千兆以太网、WIFI蓝牙模块HDMI、CAN、RS485、LVDS接口、温湿度传感器(选配)光环境传感器、六轴传感器、2路USB OTG、3路串口,CAMERA接口、ADC电位器、SPDIF、SDIO接口等


第二篇 Linux系统编程篇

什么是Linux系统编程呢?Linux系统编程也叫Linux下的高级编程。是介于应用层和驱动层之间的。内核向用户提供的接口。本章讲述编写Linux系统应用层软件常用的一些技术,包括文件IO,标准IO,进程线程操作。这些运行在系统应用层的程序直接与内核和系统核心库进行交互,只能在Linux上运行,不能跨平台,也就是不能运行在其他操作系统上(比如windows)。Linux根据UNIX发展而来,属于类UNIX操作系统,拥有UNIX特点,但是Linux作为开源软件更专注实用功能,支持更多的系统调用,从而拥有更多的新特性。

学习系统编程可以使用man手册查看API,查找用到的头文件,如“man 2 open”,使用“top”等命令查看进程状态。本文档主要通过实验例程来说明各系统调用API和各种机制的用法。

在开始系统编程前首先要搭建环境,大家可以参考本手册第二十四章安装 Samba,首先我们来了解下Linux系统编程的基本程序框架。Samba搭建好之后,我们在samba文件夹下新建linux文件夹,如下图所示:

首先来编写下Linux系统编程的基本程序框架,在linux文件夹下新建01文件夹,01文件夹里面新建test.c文件,内容如下所示。代码在配套资料“iTOP-STM32MP157开发板网盘资料汇总\09_嵌入式Linux开发指南(iTOP-STM32MP157)手册配套资料\系统编程配套程序\01”目录下。 

#include<stdio.h>
#include<stdlib.h>

int main(int argc,char *argv[])
{
        //argc:表示的是命令行中参数的个数。
        //argv:表示的是命令行中的参数
        int i;
        printf("argc is %d\n",argc);
        for(i=0;i<argc;i++){
                printf("argv[%d] is %s\n",i,argv[i]);
        };
        return 0;
}

我们在Ubuntu的Samba目录下输入以下编译test.c,如下图所示编译生成了a.out。

gcc test.c
ls

此时main()函数是没有参数的,但是我们在学习Linux系统编程的时候,大多数main函数都是带参数的,因为我们要配合命令行来给我们的程序传参数。大部分情况下,main函数的参数为int argc,char *argv[]。argc表示的命令行中参数的个数。argv表示的是命令行中的参数。

 第一部分 Linux下I/O操作

第三十章 文件IO和标准IO

文件 IO是Linux系统提供的接口,针对文件和磁盘进行操作,不带缓存机制;标准IO是C语言函数库里的标准I/O模型在stdio.h中定义,通过缓冲区操作文件,带缓存机制。Linux系统中一切皆文件,包括普通文件,目录,设备文件(不包含网络设备),管道,fifio队列,socket套接字等,在终端输入“ls -l”可查看文件类型和权限。

标准IO和文件IO常用API如下:

标准IO

文件IO

打开/创建

fopen

open

getc,fgetc,getchar,fgets,gets,

fread

read

putc,fputc,putc,fputs,puts,

fwrite

write

关闭

fclose

close

标准IO和文件IO的区别如下图所示:

文件IO是直接调用内核提供的系统调用函数,头文件是unistd.h,标准IO是间接调用系统调用函数,头文件是stdio.h,文件IO是依赖于Linux操作系统的,标准IO是不依赖操作系统的,所以在任何的操作系统下,使用标准IO,也就是C库函数操作文件的方法都是相同的。

对于文件IO来说,一切都是围绕文件操作符来进行的。在Linux系统中,所有打开的文件都有一个对应的文件描述符。文件描述符的本质是一个非负整数,当我们打开一个文件时,系统会给我们分配一个文件描述符。当我们对一个文件做读写操作的时候,我们使用open函数返回的这个文件描述符会标识该文件,并将其作为参数传递给read或者write函数。在posix.1应用程序里面,文件描述符0,1,2分别对应着标准输入,标准输出,标准错误。

 

30.1 文件IO open()

函数定义:

open():通过系统调用,可以打开文件,并返回文件描述符。

       #include <sys/types.h>

       #include <sys/stat.h>

       #include <fcntl.h>

       int open(const char *pathname, int flags);

       int open(const char *pathname, int flags, mode_t mode);

参数含义:

pathname:路径和文件名

flags:文件打开方式,可用多个标志位按位或设置,常用的标志位参数如下:

O_CREAT		要打开的文件名不存在时自动创建改文件。
O_EXCL		要和O_CREAT一起使用才能生效,如果文件存在则open()调用失败。
O_RDONLY	只读模式打开文件。
O_WRONLY	只写模式打开文件。
O_RDWR		可读可写模式打开文件。
O_APPEND	以追加模式打开文件。
O_NONBLOCK	以非阻塞模式打开。

mode: 权限掩码,对不同用户和组设置可执行,读,写权限,使用八进制数表示,此参数可不写。

返回值

open()执行成功会返回int型文件描述符,出错时返回-1。

实验代码

编写程序,在同一目录下创建并打开一个可读可写文件a.c。代码在配套资料“iTOP-STM32MP157开发板网盘资料汇总\09_嵌入式Linux开发指南(iTOP-STM32MP157)手册配套资料\系统编程配套程序\02”目录下。

#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main(int argc,char *argv[])
{
        int fd;
        fd=open("a.c",O_CREAT|O_RDWR,0666);
        if(fd<0)
        {
                printf("open is error\n");
        }
        printf("fd is %d\n",fd);
        return 0;
}

编译运行:

在Ubuntu上编译open.c,并运行a.out,如下图所示:

在程序中打开的文件描述符为3,这是因为在一个进程中至少包含三个文件描述符,即0表示标准输入stdin,1表示标准输出stdout,2表示标准错误stderr。

交叉编译open.c,通过NFS将编译好的文件拷贝到SRM32MP157开发板,如下图所示:

 

在开发板上运行结果如下图所示: 

#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
int main(int argc,char *argv[])
{
        int fd;
        fd=open("a.c",O_CREAT|O_RDWR,0666);
        if(fd<0)
        {
                printf("open is error\n");
        }
        printf("fd is %d\n",fd);
        close(fd);
        return 0;
}

30.2 文件IO close()

函数定义:

close()可以关闭文件,通过系统调用取消文件描述符到文件的映射。

  #include <unistd.h>

        int close(int fd);

参数含义:

fd:文件描述符

返回值:成功返回0;错误返回-1.

实验代码

编写程序,在同一目录下打开并创建一个可读可写文件,获取完属性后关闭。代码在配套资料“iTOP-STM32MP157开发板网盘资料汇总\09_嵌入式Linux开发指南(iTOP-STM32MP157)手册配套资料\系统编程配套程序\03”目录下。

#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
int main(int argc,char *argv[])
{
        int fd;
        fd=open("a.c",O_CREAT|O_RDWR,0666);
        if(fd<0)
        {
                printf("open is error\n");
        }
        printf("fd is %d\n",fd);
        close(fd);
        return 0;
}

编译运行:

在Ubuntu上编译open.c,如下图所示:

30.3 文件IO read()

函数定义:

read():读取文件最常用的函数,每次从fd读取count个字节,保存到buf中。

       #include <unistd.h>

       ssize_t read(int fd, void *buf, size_t count);

参数定义:

fd: 要读的文件描述符

buf: 缓冲区,存放读到的内容。

count: 每次读取的字节数

返回值:

返回值大于0,表示读取到的字节数;

等于0在阻塞模式下表示到达文件末尾或没有数据可读(EOF),并调用阻塞;

等于-1表示出错,在非阻塞模式下表示没有数据可读。

实验代码

在程序中打开a.c文件,并读取打印文件内容。代码在配套资料“iTOP-STM32MP157开发板网盘资料汇总\09_嵌入式Linux开发指南(iTOP-STM32MP157)手册配套资料\系统编程配套程序\04”目录下。

#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
int main(int argc,char *argv[])
{
        int fd;
        char buf[32]={0};
        ssize_t ret;
        fd=open("a.c",O_CREAT|O_RDWR,0666);
        if(fd<0)
        {
                printf("open is error\n");
                return -1;
        }
        printf("fd is %d\n",fd);
        ret=read(fd,buf,32);
        if(ret<0)
        {
                printf("read is error\n");
                return -2;
        }
        printf("buf is %s\n",buf);
        printf("ret is %ld\n",ret);
        close(fd);
        return 0;
}

编译运行:

在Ubuntu上编译open.c,运行a.out,如下图所示:

编辑a.c文件,内容如下图所示:

运行a.out,如下图所示,成功读取到a.c文件中的hello world! 

30.3 文件IO write() 

函数

ssize_t write(int fd, const void *buf, size_t count);

头文件

#include <unistd.h>

参数fd

文件描述符;

参数buf

缓存区,存放将要写入的数据

参数count

每次写入的个数

功能

每次从buf缓存区拿count个字节写入fd文件。

返回值

大于或等于0表示执行成功,返回写入的字节数;

返回-1代表出错。

函数定义

write():常用来写文件,定义如下:

       #include <unistd.h>

       ssize_t write(int fd, const void *buf, size_t count);

参数含义:

fd: 文件描述符;

buf: 缓存区,存放将要写入的数据;

count: 每次写入的个数。

函数功能:

每次从buf缓存区拿count个字节写入fd文件。

返回值:

大于或等于0表示执行成功,返回写入的字节数;

返回-1代表出错。

实验代码

在程序中使用write函数向标准输出(屏幕)打印hello。代码在配套资料“iTOP-STM32MP157开发板网盘资料汇总\09_嵌入式Linux开发指南(iTOP-STM32MP157)手册配套资料\系统编程配套程序\05”目录下。

#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
int main(int argc,char *argv[])
{
        int fd;
        char buf[32]={0};
        ssize_t ret;
        fd=open("a.c",O_CREAT|O_RDWR,0666);
        if(fd<0)
        {
                printf("open is error\n");
                return -1;
        }
        write(1,"hello\n",6);
        close(fd);
        return 0;
}

编译程序并运行a.out ,如下图所示,向标准输出(屏幕)写入hello。

实验代码

在程序中使用write函数向文件写入hello。代码在配套资料“iTOP-STM32MP157开发板网盘资料汇总\09_嵌入式Linux开发指南(iTOP-STM32MP157)手册配套资料\系统编程配套程序\05”目录下。

#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
int main(int argc,char *argv[])
{
        int fd;
        char buf[32]={0};
        ssize_t ret;
        fd=open("a.c",O_CREAT|O_RDWR,0666);
        if(fd<0)
        {
                printf("open is error\n");
                return -1;
        }
        write(fd,"hello\n",6);
        close(fd);
        return 0;
}

运行测试

编译运行打开a.out,并且查看写入的文件a.c,如下图所示,a.c文件成功写入hello。

30.4综合练习(一)

实验要求

在程序中通过命令行操作,把a.c文件里面的内容写到b.c

实验代码

代码在配套资料“iTOP-STM32MP157开发板网盘资料汇总\09_嵌入式Linux开发指南(iTOP-STM32MP157)手册配套资料\系统编程配套程序\06”目录下。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc, char *argv[])
{

    //步骤一:判断命令行的参数
    if(argc != 3)
    {
        printf("Usage:%s <src file> <obj file>\n", argv[0]);
    }
    // 步骤二:定义变量
    int fd_src;
    int fd_obj;
    char buf[32] = {0};
    ssize_t ret;
    // 步骤三:打开文件获得文件描述符
    fd_src = open(argv[1], O_RDWR);
    if (fd_src < 0)
    {
        printf("open is error\n");
        return -1;
    }
    fd_obj = open(argv[2], O_CREAT | O_RDWR, 0666);
    if (fd_obj < 0)
    {
        printf("open is error\n");
        return -2;
    }
    // 步骤四:读写操作
    while((ret=read(fd_src,buf,32))!=0)
    {
        write(fd_obj,buf,ret);
    }
    // 步骤五:关闭文件描述符
    close(fd_src);
    close(fd_obj);
    return 0;
}

编译测试

在Ubuntu上编译open.c,首先查看a.c的内容,然后运行程序,再查看b.c的内容,如下图所示,成功将a.c文件的内容拷贝到b.c文件。

30.5文件IO lseek() 

函数

off_t lseek(int fd, off_t offset, int whence);

头文件

#include <sys/types.h>

#include <unistd.h>

参数fd

文件描述符

参数off_t offset

偏移量,单位是字节的数量,可以正负,如果是负值表示向前移动;如果是正值,表示向后移动。

参数whence

当前位置的基点,可以使用以下三组值。

SEEK_SET:相对于文件开头

SEEK_CUR:相对于当前的文件读写指针位置

SEEK_END:相对于文件末尾

功能

每次从buf缓存区拿count个字节写入fd文件。

返回值

成功返回当前位移,失败返回-1

函数定义

lseek():移动文件的读写位置,定义如下:

       #include <sys/types.h>

       #include <unistd.h>

       off_t lseek(int fd, off_t offset, int whence);

参数含义:

fd: 文件描述符;

off_t offset: 偏移量,单位是字节的数量,可以正负,如果是负值表示向前移动;如果是正值, 表示向后移动。

whence: 当前位置的基点,可以使用以下三组值。

SEEK_SET:相对于文件开头

SEEK_CUR:相对于当前的文件读写指针位置

SEEK_END:相对于文件末尾

函数功能:

每次从buf缓存区拿count个字节写入fd文件。

返回值:

成功返回当前位移,失败返回-1.

举个例子

  1. 把文件位置指针设置为100  lseek(fd,100,SEEK_SET);
  2. 把文件位置设置成文件末尾  lseek(fd,0,SEEK_END);
  3. 确定当前的文件位置 lseek(fd,0,SEEK_CUR);

实验代码

在程序中使用lseek函数移动文件读写位置,代码在配套资料“iTOP-STM32MP157开发板网盘资料汇总\09_嵌入式Linux开发指南(iTOP-STM32MP157)手册配套资料\系统编程配套程序\07”目录下。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    int fd;
    char buf[32] = {0};
    ssize_t ret;
    fd = open("a.c", O_CREAT | O_RDWR, 0666);
    if (fd < 0)
    {
        printf("open is error\n");
        return -1;
    }
   // printf("fd is %d\n", fd);
    ret = read(fd, buf, 32);
    if (ret < 0)
    {
        printf("read is error\n");
        return -2;
    }
    printf("buf is %s\n", buf);
    printf("ret is %ld\n", ret);
    lseek(fd,0,SEEK_SET);
    ret = read(fd, buf, 32);
    printf("ret is %ld\n", ret);
    close(fd);
    return 0;
}

运行测试

编译运行打开a.out ,a.c里面里面有hello world!,当使用lseek函数移动读写位置时,再次读a.c文件的内容,依旧可以读到a.c的内容,如下图所示:

实验代码

在程序中读a.c文件的2字节,使用lseek函数确定文件的当前位置。代码在配套资料“iTOP-STM32MP157开发板网盘资料汇总\09_嵌入式Linux开发指南(iTOP-STM32MP157)手册配套资料\系统编程配套程序\07”目录下。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    int fd;
    char buf[32] = {0};
    ssize_t ret;
    fd = open("a.c", O_CREAT | O_RDWR, 0666);
    if (fd < 0)
    {
        printf("open is error\n");
        return -1;
    }
   // printf("fd is %d\n", fd);
    ret = read(fd, buf, 2);
    if (ret < 0)
    {
        printf("read is error\n");
        return -2;
    }
    printf("buf is %s\n", buf);
    printf("ret is %ld\n", ret);
    ret=lseek(fd,0,SEEK_CUR);
   // ret = read(fd, buf, 32);
    printf("ret is %ld\n", ret);
    close(fd);
    return 0;
}

运行测试

编译运行打开a.out ,a.c里面里面有hello world!运行结果如下图所示:

实验代码

在程序中读a.c文件,使用lseek函数确定文件的长度。代码在配套资料“iTOP-STM32MP157开发板网盘资料汇总\09_嵌入式Linux开发指南(iTOP-STM32MP157)手册配套资料\系统编程配套程序\07”目录下。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
    int fd;
    char buf[32] = {0};
    ssize_t ret;
    fd = open("a.c", O_CREAT | O_RDWR, 0666);
    if (fd < 0)
    {
        printf("open is error\n");
        return -1;
    }
   // printf("fd is %d\n", fd);
    ret = read(fd, buf, 2);
    if (ret < 0)
    {
        printf("read is error\n");
        return -2;
    }
    printf("buf is %s\n", buf);
    printf("ret is %ld\n", ret);
    ret=lseek(fd,0,SEEK_END);
   // ret = read(fd, buf, 32);
    printf("ret is %ld\n", ret);
    close(fd);
    return 0;
}

运行测试

编译运行打开a.out ,a.c里面里面有hello world!运行结果如下图所示:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值