一、先来了解下什么是文件I/O和标准I/O:
文件I/O:文件I/O称之为不带缓存的IO(unbuffered I/O)。不带缓存指的是每个read,write都调用内核中的一个系统调用。也就是一般所说的低级I/O——操作系统提供的基本IO服务,与os绑定,特定于linix或unix平台。
标准I/O:标准I/O是ANSI C建立的一个标准I/O模型,是一个标准函数包和stdio.h头文件中的定义,具有一定的可移植性。标准I/O库处理很多细节。例如缓存分配,以优化长度执行I/O等。标准的I/O提供了三种类型的缓存。
(1)全缓存:当填满标准I/O缓存后才进行实际的I/O操作。
(2)行缓存:当输入或输出中遇到新行符时,标准I/O库执行I/O操作。
(3)不带缓存:stderr就是了。
二、二者的区别
文件I/O 又称为低级磁盘I/O,遵循POSIX相关标准。任何兼容POSIX标准的操作系统上都支持文件I/O。标准I/O被称为高级磁盘I/O,遵循ANSI C相关标准。只要开发环境中有标准I/O库,标准I/O就可以使用。(Linux 中使用的是GLIBC,它是标准C库的超集。不仅包含ANSI C中定义的函数,还包括POSIX标准中定义的函数。因此,Linux 下既可以使用标准I/O,也可以使用文件I/O)。
通过文件I/O读写文件时,每次操作都会执行相关系统调用。这样处理的好处是直接读写实际文件,坏处是频繁的系统调用会增加系统开销,标准I/O可以看成是在文件I/O的基础上封装了缓冲机制。先读写缓冲区,必要时再访问实际文件,从而减少了系统调用的次数。
文件I/O中用文件描述符表现一个打开的文件,可以访问不同类型的文件如普通文件、设备文件和管道文件等。而标准I/O中用FILE(流)表示一个打开的文件,通常只用来访问普通文件。
三、相关API
系统IO
1、open()
#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------包含路径的文件名,例如“./a.txt”
flags---------文件标志
O_RDONLY----只读
O_WRONLY----只写
O_RDWR------可读可写
O_CREAT-----如果文件不存在,新建文件,此时mode才有用
O_EXCL------与O_CREAT配合使用,可以用来通过返回值判断文件是否新建成功
O_TRUNC-----在文件存在&&是普通文件&&能写入的情况下,文件内容清空
O_APPEND----打开文件时,把文件读写指针定位在文件末尾,可追加写入内容
mode----------如果文件为新建,指定权限为mode,如:0777
返回值:成功 返回文件描述符
失败 返回 -1
2、read()
#include <unistd.h>
ssize_t read(int fildes, void *buf, size_t nbyte);
功能:读取描述符为fildes的文件的内容,放入buf指向的内存中,nbyte是期望读取的字节数
返回值:成功,返回实际读取的字节数(实际读取的字节数小于或等于nbyte)
失败,返回-1
3、write()
#include <unistd.h>
ssize_t write(int fildes, const void *buf, size_t nbyte);
功能:把buf指向的内存中的内容,写入描述符为fildes的文件,nbyte是期望写入的字节数
返回值:成功,返回实际写入的字节数(实际写入的字节数小于或等于nbyte)
失败,返回-1
4、close()
#include <unistd.h>
int close(int fildes);
功能:关闭描述符为fildes的文件
返回值:成功返回0
失败返回-1
5、lseek()
#include <unistd.h>
off_t lseek(int fildes, off_t offset, int whence);
功能:定位描述符为fd的文件的读写指针
参数: fd---文件描述符
offset---基于基点的偏移量,正数向后偏移,负数向前偏移
whence---基点
SEEK_SET----文件开头
SEEK_END----文件末尾
SEEK_CUR----当前位置
返回值:成功 返回从文件开头到定位位置的字节数
失败 返回-1
6、ioctl()
#include <stropts.h>
int ioctl(int fildes, int request, ... /* arg */);
功能:对描述符位fildes文件,进行request操作(一般是驱动中给出命令字(读写之外的其它操作),用户程序通过用的命令字,操控硬件设备)
request---->SET_BAUD //设置波特率
REDA_BAUD //读取波特率
FBIOGET_VSCREENINFO //显示屏命令
#define 查询屏幕大小的命令 (有固定格式要求的32位整数)
fd = open("/dev/fb0",.....)
struct struct fb_var_screeninfo var_info;
ioctl(fd,FBIOGET_VSCREENINFO,&var_info)
struct fb_var_screeninfo {
__u32 xres; //x方向的像素点个数
__u32 yres; //y方向的像素点个数
...
__u32 bits_per_pixel;} //每个像素点用多少位表示颜色值
7、fcntl()
#include <fcntl.h>
int fcntl(int fildes, int cmd, ...);
功能:根据文件描述词来操作文件的特性
参数:cmd------>操作命令
F_DUPFD :复制文件描述词 。
FD_CLOEXEC :设置close-on-exec标志。如果FD_CLOEXEC位是0,执行execve的过程中,文件保持打开。反之则关闭。
F_GETFD :读取文件描述词标志。
F_SETFD :设置文件描述词标志。
F_GETFL :读取文件状态标志。
F_SETFL :设置文件状态标志。
其中O_RDONLY, O_WRONLY, O_RDWR, O_CREAT, O_EXCL, O_NOCTTY 和 O_TRUNC不受影响, 可以更改的标志有 O_APPEND,O_ASYNC, O_DIRECT, O_NOATIME 和 O_NONBLOCK。
F_SETLK:在指定的字节范围获取锁(F_RDLCK,F_WRLCK)或者释放锁(F_UNLCK)。如果与另一个进程的锁操作发生冲突,返回 -1并将errno设置为EACCES或EAGAIN。
F_SETLKW:行为如同F_SETLK,除了不能获取锁时会睡眠等待外。如果在等待的过程中接收到信号,会立即返回并将errno置为EINTR。
F_GETLK:获取文件锁信息。
F_UNLCK:释放文件锁。
返回值:成功 根据不同命令字而不同
失败 -1
8、mmap()
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
功能:把描述符为fd的文件,映射到一片内存空间
参数: addr-----指定地址映射,一般设置NULL,表示让系统决定映射的位置
length----映射的内存的大小,以字节为单位
port----对内能够做何种操作
PROT_EXEC Pages may be executed.可执行
PROT_READ Pages may be read.可读
PROT_WRITE Pages may be written.可写
PROT_NONE Pages may not be accessed.不可访问
flags----映射标志
MAP_SHARED--共享
MAP_PRIVATE---私有
offset---一般设置为0
返回值 成功---返回内存首地址
失败---返回(void *)-1 MAP_FAILED
9、munmap()
#include <sys/mman.h>
int munmap(void *addr, size_t length);
功能:取消映射
参数: addr----要取消映射的内存的基地址
length---取消映射内存的大小,以字节为单位
10、dup()\dup2()
#include <unistd.h>
int dup(int fildes);
int dup2(int fildes, int fildes2);
功能:复制文件描述符
参数: fildes--->要复制的文件描述符
fildes2-->指定的新的文件描述符
返回值:成功 返回新的文件描述符
失败 -1
11、显示屏\触摸屏("/dev/fb0","/dev/input/event0")
相关结构体:
struct fb_var_screeninfo { //显示屏
__u32 xres; //x方向的像素点个数
__u32 yres; //y方向的像素点个数
...
__u32 bits_per_pixel;} //每个像素点用多少位表示颜色值
struct input_event {
struct timeval time; -----发生时间
__u16 type; ----触摸屏事件类型EV_ABS
__u16 code; ---ABS_X ABS_Y
__s32 value;} ----坐标值,触摸屏有触摸动作时,打出x y方向的坐标值
标准C库IO
1、fopen()
#include <stdio.h>
FILE *fopen(const char *path, const char *mode);
功能:打开或创建文件(获取指定文件的文件指针)
参数:path---->指向包含路径的文件名
mode---->文件模式标志
r 以只读方式打开文件,要求文件必须存在
r+ 以读/写方式打开文件,要求文件必须存在
w 以只写方式打开文件,如果文件不存在会创建新文件,如果存在会将其内容清空
w+ 以读/写方式打开文件,如果文件不存在会创建新文件,如果存在会将其内容清空
a 以只写方式打开文件,文件如果不存在会创建新文件
且文件位置偏移量被自动定位到文件末尾(即以追加方式写数据)
a+ 以读/写方式打开文件,文件如果不存在会创建新文件
且文件位置偏移量被自动定位到文件末尾(即以追加方式写数据)
返回值:成功 返回FILE*
失败 返回NULL
2、fclose()
#include <stdio.h>
int fclose(FILE *stream);
功能:关闭文件
参数:stream ---->要关闭的文件的指针
返回值:成功 返回0
失败 返回EOF
3、fread()
#include <sys/ioctl.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:从stream对应的文件中读取 size *nmemb个字节,存入ptr指向的内存
参数: ptr------自定义缓冲区指针
size-----读取的块的大小
nmemb----期望读取到的块数
stream---即将被读取数据的文件指针
返回值:成功 返回的块数等于期望读到的块数
失败 返回的块数小于期望的块数,表示出错或到达文件末尾
4、fwrite()
#include <sys/ioctl.h>
size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
功能:把ptr指向的内存中的size *nmemb个字节写入stream对应的文件
参数: ptr------自定义缓冲区指针
size-----写入的块的大小
nmemb----期望写入的数据块个数
stream---即将被写入数据的文件指针
返回值:成功 返回的块数等于期望写入的块数
失败 返回的块数小于期望的块数
5、O操作相关函数
#include <sys/ioctl.h>
#include <stdio.h>
int fputc(int c, FILE *stream);---把c(字符)输出到stream对应的文件
int fputs(const char *s, FILE *stream);----把字符串s输出到stream对应的文件
int putc(int c, FILE *stream);-----把c输出到stream对应的文件
int putchar(int c);------只能通过stdout 把c输出到屏幕
int puts(const char *s);----只能向stdout对应的屏幕输出字符串s
6、I操作相关函数
#include <sys/ioctl.h>
#include <stdio.h>
int fgetc(FILE *stream);---从stream对应的文件中读取一个字符
char *fgets(char *s, int size, FILE *stream);----从stream对应的文件中最多读取大小为size-1个字符,存入s指向的位置 注意:读取过程中遇到‘\n’或者EOF停止
int getc(FILE *stream);---从stream对应的文件中读取一个字符
char *gets(char *s);-----从自定义缓冲区s中读取数据,由于没有指定s的大小,容易造成溢出导致程序出现段错误
int getchar(void);------只能通过stdin对应标准输入设备获取字符
7、feof()/ferror()
#include <sys/ioctl.h>
int feof(FILE *stream);
功能:测试stream对应的文件读写操作是否到末尾
返回值:已到末尾返回非零值(逻辑真值)
未到末尾返回零值(逻辑假值)
int ferror(FILE *stream)
功能:测试stream对应的文件读写操作是否出错
返回值:出错返回非零值(逻辑真值)
未出错返回零值(逻辑假值)
8、fseek()/ftell()
#include <sys/ioctl.h>
int fseek(FILE *stream,long offset,int whence);----设定指定文件的当前位置偏移量
参数: stream---需要设置位置偏移量的文件指针
offset---新位置偏移量相对基准点的偏移
whence---基准点(SEEK_SET:文件开头处;SEEK_CUR:当前位置;SEEK_END:文件末尾处)
返回值:成功 返回0
失败 返回-1
long ftell(FILE *stream);
功能:返回值是stream对应的文件的读写指针位置
9、缓冲相关
#include <stdio.h>
int fflush(FILE *stream); //刷缓冲满
int setvbuf(FILE *stream, char *buf, int mode, size_t size);
功能:设置stream对应文件的缓冲位置、类型、大小
参数: buf------指向缓冲区
mode-----缓冲类型
_IONBF unbuffered 不缓冲
_IOLBF line buffered 行缓冲
_IOFBF fully buffered 满缓冲
size-----缓冲区的大小
注意:标准输出默认使用行缓冲,普通文件默认使用全缓冲,标准出错不缓冲。
10、stat()/fstat()/lstat()
#include <sys/stat.h>
int stat(const char *restrict path, struct stat *restrict buf);
int fstat(int fildes, struct stat *buf);0
int lstat(const char *restrict path, struct stat *restrict buf);
功能:获取文件的元数据(类型、权限、大小等)
参数: path--文件路径
fildes--文件描述符
buf--属性结构体(保存获取到的数据)
返回值:成功 0
失败 NULL
struct stat {
dev_t st_dev; /* ID of device containing file 普通文件所在存储器的设备号*/
ino_t st_ino; /* inode number 文件索引号*/
mode_t st_mode; /* protection 文件类型、文件权限*/
nlink_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of owner 文件所有者的UID*/
gid_t st_gid; /* group ID of owner 文件所属组的GID*/
dev_t st_rdev; /* device ID (if special file) 特殊文件设备号*/
off_t st_size; /* total size, in bytes 文件大小*/
blksize_t st_blksize; /* blocksize for filesystem I/O */
blkcnt_t st_blocks; /* number of 512B blocks allocated */
....
}
目录检索
1、mkdir
#include <sys/stat.h>
#include <sys/types.h>
int mkdir(const char *pathname, mode_t mode);
功能:新建一目录文件,并指定权限
参数: pathname---包含路径的文件名
mode-----权限
返回值:成功 0
失败 -1
2、opendir
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
功能:打开一个目录文件
返回值:成功返回DIR *
失败返回NULL
3、readdir
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
功能:读取目录文件的内容(目录项)
struct dirent {
ino_t d_ino; /* inode number */
off_t d_off; /* not an offset; see NOTES */
unsigned short d_reclen; /* length of this record */
unsigned char d_type; /* type of file; not supported
by all filesystem types */
char d_name[256]; /* filename */
};
其中d_type(文件类型)成员取值如下:
DT_BLK This is a block device.
DT_CHR This is a character device.
DT_DIR This is a directory.
DT_FIFO This is a named pipe (FIFO).
DT_LNK This is a symbolic link.
DT_REG This is a regular file.
DT_SOCK This is a UNIX domain socket.
DT_UNKNOWN The file type is unknown.
返回值:成功返回struct dirent *
出错或到了目录末尾返回NULL
4、chdir()
#include <dirent.h>
int chdir(const char *path);
功能:切换到path目录下
返回值:切换成功返回0
出错返回-1