文件IO基础知识

学习文件IO之前,先了解一下什么是库函数和系统调用。

库函数:顾名思义是把函数放到库里。是把一些常用到的函数编完放到一个库文件里,供别人用,别人用的时候把它所在的文件名#include<>加到里面就可以了。可分为两类,一类是c语言标准规定的库函数,一类是编译器特定的库函数。

系统调用:是操作系统为用户态运行的进程与硬件设备(如CPU、磁盘、打印机等)进行交互提供的一组接口函数;
文件描述符
对于内核而言,所有打开的文件、设备、网络socket都是通过文件描述符引用,文件描述符是一个非负整数。当打开一个现有文件或创建一个新文件时,内核向进程返回一个文件描述符。当读、写一个文件时,使用open或creat返回的文件描述符标识该文件,将其作为参数传给read或write。

注意:应用程序运行的时候,系统将会为该进程默认打开三个文件描述符:
1.标准输入:STDIN_FILENO (0)
2.标准输出 : STDOUT_FILENO (1)
3.标准出错: STDERR_FILENO (2)

文件描述符的变化范围是: 0~OPEN_MAX-1

下面依次介绍linux系统调用函数:
1.open()
int open(const char path, int oflag, … /*mode_t mode/);
返回值 int fd 文件描述符(file description), open系统调用返回的文件描述符一定是最小的、未使用的文件描述符数值

参数
path: 要打开的文件、设备的路径名
oflag: 由多个选项进行“或”运算构造oflag参数
必选: O_RDONLY (只读)、 O_WRONLY(只写),O_RDWR(读写)
可选: O_APPEND 每次写时都追加到文件的尾端。O_CREAT 文件不存在则创建它,使用该选项需要第三个mode
O_NONBLOCK 如果path是一个FIFO、块设备、字符特殊文件则此选项为文件的本次打开和后续的I/O操作设置非阻塞模式方式。
O_TRUNC 如果文件存在,而且为只写或读写成功打开,则将其长度截取为0;
O_EXEC、O_SEARCH、O_CLOEXEC、O_NOCTTY….
mode: oflag带O_CREAT选项时,必须带该参数用来指定打开文件的权限模式,如066。
例: int fd; fd = open(“text.txt”, O_RDWR|O_CREAT|O_TRUNC, 0666);
fd = open(“text.txt”, O_WRONLY|O_APPEND);

总结
(1).在windows下编程,系统不提供open(),write()函数,打开文件用fopen()库函数时,所有操作系统都可以调用。
(2).open()函数里面的参数如果有O_CREAT这个参数时,则一定要有三个参数

2.creat()
int creat(const char *path, mode_t mode);
此函数用来创建一个新文件并返回其fd
**它等价于**open(path, O_WRONLY|O_CREAT|O_TRUNC, mode);
例: int fd; fd=creat(“text.txt”, 0644);

3.close()
该函数用来关闭一个打开的文件,关闭一个文件时还会释放该进程加在该文件上的所有记录锁。当一个进程终止时,内核自动关闭它所有打开的文件。
int close(int fd);

ps:编程一旦用了open()函数,一定要close()关闭,否则文件描述符一直会被占用。

4.lseek()
每打开一个文件时都有一个与其关联的“当前文件偏移量”。它通常是一个非负整数,用以度量从文件开始处计算的字节数。通常读写操作都是从当前文件偏移量处开始,并使用偏移量增加所读写的字节数。按系统默认的情况,当打开一个文件时,除非指定O_APPEND选项,否则该偏移量被设置为0.

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

注意:whence:
SEEK_SET, 则将该文件偏移量设置为距文件开始处offset个字节;
SEEK_CUR,则该文件的偏移量设置为当前值加offset,offset可为正或负;
SEEK_END,则将该文件偏移量设置为长度加offset,offset可正可负;
off_t pos;
pos = lseek(fd, 0, SEEK_CUR);

lseek()函数运用举例,如下图:
这里写图片描述
该程序的目的是创建文件text.txt,并向文件里面写内容,并将内容输出在屏幕上。

5.read()/write()
(1)read()函数用来从打开的文件中读取数据:
ssize_t read(int fd, void *buf, size_t nbytes);
如read成功,则返回读到的字节数。如已到达文件的尾端,则返回0。
(2)write()函数用来往打开的文件中写入数据:
ssize_t write(int fd, const void *buf, size_t nbytes);
如write成功,则返回实际写入的字节数,失败返回-1。

注意:系统调用出错处理
(1)大部分的Linux系统调用返回值都是0表示成功,-1表示失败。在库函数中有个整形类型的errno变量,每个errno值对应着以字符串表示的错误类型。如果系统调用出错,则该函数将重新设置errno的值,通过该信息我们可以查看系统调用出错的具体原因
(2)perror() 用来将上一个函数发生错误的原因输出到标准出错(stderr)。参数 s 所指的字符串会先打印出,后面再加上错误原因字符串。此错误原因依照全局变量errno的值来决定要输出的字符串
(3)strerror通过标准错误的标号,获得错误的描述字符串 ,将单纯的错误标号转为转为字符串描述,方便用户查找错误。

例:
int main(int argc, char *argv)
{
int fd = -1;
char buf[1024];
//char *buf;
fd = open(“file.txt”, O_RDWR|O_CREAT|O_TRUNC);
if(fd < 0)
{
perror(“Open failure”);
printf(“Open %s failure:[%d] %s\n”, “file.txt”, errno, strerror(errno));
return ;
}
write(fd, “Hello”, 5);
memset(buf, 0, sizeof(buf));
read(fd, buf, sizeof(buf));
printf(“file content: %s\n”, buf);
close(fd);
}

6.dup() 和 dup2()
以下两个函数都可以用来复制一个现有的文件描述符。
int dup(int fd);
int dup2(int fd, int fd2);
注意:由dup返回的新文件描述符一定是当前可用文件描述符中的最小数值。
dup2可以用fd2参数指定新描述符的值。如果fd2已经打开,则先关闭。如fd等于fd2, 则
dup2返回fd2, 而不关闭它。
使用这两个函数可以用来实现标注输入、标准输出、标准出错重定向:
int fd = -1;
fd = open(“std.txt”, O_RDWR|O_CREAT|O_TRUNC, 0666);
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
printf(“Hello Word!\n”);

例:
int main(int argc, char *argv)
{
int fd = -1;
fd = open(“file.txt”, O_RDWR|O_CREAT|O_TRUNC);
if(fd < 0)
{
printf(“Open %s failure:[%d] %s\n”, “file.txt”, errno, strerror(errno));
return ;
}
dup2(fd, 1);
printf(“fd=%d”, fd);
close(fd);
}

8.ioctl()
ioctl()函数一直是I/O操作的杂物箱,不能用本章中其他函数表示的I/O操作通常都能用ioctl()表示。终端I/O、设备I/O是使用ioctl()最多的地方。
int ioctl(int fd, int cmd, …);
fd: 文件描述符
cmd: 命令字,这个参数需要与设备驱动中的cmd保持一致。
第三个参数可选
注意:写LED驱动时,将会在驱动中实现该函数,在应用程序空间再调用该函数
控制LED的亮和灭。
int fd = -1;
fd = open(“/dev/led”, O_RDWR);
ioctl(fd, TURN_OFF, 3);
close(fd);

9.stat系列函数
stat系列函数用来返回文件或目录的相关信息
int stat(const char * restrict path, struct stat *restrict buf);
int fstat(int fd, struct stat *buf);
struct stat
{
mode_t st_mode; struct timespec st_atime;
ino_t st_ino; struct timespec st_mtime;
dev_t st_dev; struct timespec st_ctime;
dev_t st_rdev; blksize_t st_blksize;
nlink_t st_nlink; blkcnt_t st_blocks;
uid_t st_uid; }
gid_t st_gid;
off_t st_size;
文件类型: 普通文件(-)、目录文件(d)、块设备(b)、字符设备(c)、FIFO(p)、套接字
socket(s)、符号链接(l)

int main (int argc, char **argv)
{
struct stat stbuf;
stat(“file.txt”, &stbuf);
printf(“File size: %d bytes UID:%d GID:%d\n”,
stbuf.st_size, stbuf.st_uid, stbuf.st_gid);
return 0;
}

10.access()
access可以用来测试文件是否存在或测试其权限位:
int access(const char *path, int mode);
mode: F_OK、R_OK、W_OK、X_OK
(1)测试文件是否存在
if( !(access(“test.txt”, F_OK)) ) // 返回0表示存在;返回-1表示不存在。
{
printf(“File exist\n”);
}
(2)测试文件是否可读可写
if( !(access(”test.txt”, R_OK|W_OK)) ) // 返回0表示存在;返回-1表示不存在。
{
printf(“File mode is read/write \n”);
}

11.unlink()/rename
int unlink(const char *path);
调用该函数将path指定的文件的链接数减1,如果对该文件还有其他链接存在,则仍可以通过其他链接访问该文件的数据。
只有当链接记数达到0时,该文件的内容才可被删除。如果有进程打开了该文件,其内容也不能被删除。关闭一个文件时,内核首先检查打开该文件的进程个数,如果这个记数达到0,内核再去检查它的链接记数,如果记数也是0,那么就删除该文件内容。

int rename(const char *oldname, const char *newname);
ps:调用该函数可以实现文件的重命名

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值