Liunx文件IO

基本文件操作

  • 文件操作:
    • 在Linux中要操作一个文件,一般是先open打开一个文件,得到文件描述符,然后对文件进行读写操作(或其他操作),最后使用close()关闭文件即可(如果不关闭文件会造成文件的损坏);
    • 文件平时是存放在块设备的文件系统文件中的,我们把这种文件叫静态文件,当我们去打开一个文件时,Linux内核做的操作包括:内核在进程中建立一个打开文件的数据结构,记录下我们打开的这个文件;内核在内存中申请一段内存,并且将静态文件中的内容读取到内核中特定地址管理存放(叫动态文件);
    • 打开文件以后,以后对这个文件的操作,都是针对内存中的这一份动态文件的,并且不是针对静态文件的,当然我们对动态文件进行读写以后,此时内存中动态文件和块设备中的静态文件就不同步了,当我们close关闭动态文件时,close内部内核将内存中的动态文件的内容去更新(同步)块设备中的静态文件;这么设计,不直接对块设备直接操作。是因为块设备读写非常不灵活,是按块读写的,而内存是按字节单位操作的,而且随机操作,很灵活。

文件描述符:

  • 内核为了高效管理已被打开的文件所创建的索引,其是一个非负整数(通常是小整数),用于指代被打开的文件,所有执行I/O操作的系统调用都通过文件描述符。程序刚刚启动的时候,0(宏 STDIN_FILENO)是标准输入,1(宏 STDOUT_FILENO)是标准输出,2(宏 STDERR_FILENO)是标准错误。如果此时去打开一个新的文件,它的文件描述符会是3。POSIX标准要求每次打开文件时(含socket)必须使用当前进程中最小可用的文件描述符号码。
  • 文件描述符的作用域就是当前进程,出了这个进程文件描述符就没有意义了。

系统调用(函数) :

open()/creat()函数

用于打开或创建文件,在打开或创建文件时可以指定文件的属性及用户的权限等各种参数。
在这里插入图片描述

所需头文件

  • #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)
  • int creat(const char *pathname, mode_t mode)

函数参数:

  • 1.pathname:被打开的文件名(包含路径)
  • 2.flags:文件的打开方式
    • O_RDONLY:以只读方式打开文件
    • O_WRONLY:以只写方式打开文件
    • O_RDWR:以读/写方式打开文件
    • O_CREAT:如果文件不存在,就创建一个新的文件,并且第三个参数为其设置文件权限
    • O_APPEND:以添加方式打开文件,在打开文件的同时,文件指针指向文件的末尾,即将写入的数据添加文件的末尾
    • O_TRUNC:若文件已经存在,则删除文件文件中的全部原有数据,并且设置文件大小为0
    • O_EXCL:检测文件是否已经存在,如果使用该参数是文件存在,则返回错误信息,此时open是原子操作,防止多个进程同时创建同一个文件
  • 3.mode:设置新创建文件的存储权限,只有在flags参数中有O_CREAT时或使用creat()函数时使用;其中R/W/X分别表示读/写/执行;可使用八进制法设置,常用的有0600,0644等;创建文件时,指定文件访问权限。权限同时受 umask 影响。结论为:
    文件权限 = mode & ~umask

函数返回值:

  • 成功:返回文件描述符(整数);
  • 失败:返回-1,设置errno;

close()函数

用于关闭一个被打开的文件。 当一个进程终止时, 所有被它打开的文件都由内核自动关闭。

所需头文件:

  • #include <unistd.h>

函数原型:

  • int close(int fd)

函数参数:

  • fd:欲关闭所对应的文件描述符

函数返回值:

  • 成功:0;
  • 失败:-1;

write()函数

用于向打开的文件写数据, 写操作从文件的当前指针位置开始, 对磁盘文件进行写操作, 若磁盘已满或超出该文件的长度, 则 write()函数返回失败。
在这里插入图片描述

所需头文件:

  • #include <unistd.h>

函数原型:

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

函数参数:

  • fd:文件描述符
  • buf:指定存储器写入数据的缓冲区
  • count:指定写入的字节数

函数返回值:

  • 成功:以写的字节数;
  • 失败:-1;

read()函数

用于将从指定的文件描述符中读出的数据放到缓存区中, 并返回实际读入的字节数。 若返回 0, 则表示没有数据可读, 即已达到文件尾。 读操作从文件的当前指针位置开始。 当从终端设备文件中读出数据时, 通常一次最多读一行。在这里插入图片描述
所需头文件:

  • #include <unistd.h>

函数原型:

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

函数参数:

  • fd:文件描述符
  • buf:指定存储器读出数据的缓冲区
  • count:指定读取的字节数

函数返回值:

  • 成功:读到的字节数;
  • 0:已读到文件尾;
  • 失败:-1;

lseek()函数

用于在指定的文件描述符中将文件指针定位到相应的位置。 它只能用在可定位(可随机访问) 文件操作中。 注意在管道、 套接字和大部分字符设备文件是不可定位的, 所以在这些文件的操作中无法使用 lseek()调用。

每个打开的文件都记录着当前读写位置,打开文件时读写位置是 0,表示文件开头,通常读写多少个字节就会将读写位置往后移多少个字节。但是有一个例外,如果以 O_APPEND方式打开,每次写操作都会在文件末尾追加数据,然后将读写位置移到新的文件末尾。
在这里插入图片描述

所需头文件:

  • #include <sys/types.h>
  • #include <unistd.h>

函数原型:

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

函数参数:

  • fd:文件描述符
  • offset: 偏移量,每一次读写操作所需要移动的距离,单位是字节,可正可负(前移,后移)
  • whence:当前位置的基点
    • SEEK_SET:当前位置为文件的开头,新位置为偏移量的大小
    • SEEK_END:当前位置为文件的结尾,新位置为文件的大小加上偏移量的大小
    • SEEK_CUR:当前位置为文件指针的位置,新位置为当前位置加上偏移量

函数返回值:

  • 成功:返回值是较文件起始位置向后的偏移量;
  • 失败:-1;

lseek函数 常见应用:

  1. 使用 lseek 拓展文件:write 操作才能实质性的拓展文件。单 lseek 是不能进行拓展的。
    一般:

lseek(fd,100,SEEK_END)//拓展文件100字节
write(fd, “\0”, 1);//引起io操作
lseek()引起空洞:之前有提到过文件当前偏移量是可以大于当前文件长度的,如果在这种情况下还进行文件写入是允许的,但是会形成文件空洞。空洞的部分用\0代替,但是空洞并不占用磁盘块。

  1. 通过 lseek 获取文件的大小:lseek(fd, 0, SEEK_END);
#include <stdio.h>
#include <error.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

int main (int argc,char *argv[])
{
	int fd = open(argv[1],O_RDWR);
	if(fd == -1){
		perror("open error");
		exit(1);
	}
	int len = lseek(fd,0,SEEK_END);//获取文件大小
	printf("file len:%d\n",len);
	close(fd);
	return 0;
}

两个查看文件内容的的指令:
od -tcx filename 查看文件的 16 进制表示形式
od -tcd filename 查看文件的 10 进制表示形式

错误处理函数

错误号:errno
查看错误号:
/usr/include/asm-generic/errno-base.h
/usr/include/asm-generic/errno.h

  • perror 函数: void perror(const char *s);
  • strerror 函数: char *strerror(int errnum);

#define EPERM 1 /* Operation not permitted /
#define ENOENT 2 /
No such file or directory /
#define ESRCH 3 /
No such process /
#define EINTR 4 /
Interrupted system call /
#define EIO 5 /
I/O error /
#define ENXIO 6 /
No such device or address /
#define E2BIG 7 /
Argument list too long /
#define ENOEXEC 8 /
Exec format error /
#define EBADF 9 /
Bad file number /
#define ECHILD 10 /
No child processes /
#define EAGAIN 11 /
Try again /
#define ENOMEM 12 /
Out of memory /
#define EACCES 13 /
Permission denied /
#define EFAULT 14 /
Bad address /
#define ENOTBLK 15 /
Block device required /
#define EBUSY 16 /
Device or resource busy /
#define EEXIST 17 /
File exists /
#define EXDEV 18 /
Cross-device link /
#define ENODEV 19 /
No such device /
#define ENOTDIR 20 /
Not a directory /
#define EISDIR 21 /
Is a directory /
#define EINVAL 22 /
Invalid argument /
#define ENFILE 23 /
File table overflow /
#define EMFILE 24 /
Too many open files /
#define ENOTTY 25 /
Not a typewriter /
#define ETXTBSY 26 /
Text file busy /
#define EFBIG 27 /
File too large /
#define ENOSPC 28 /
No space left on device /
#define ESPIPE 29 /
Illegal seek /
#define EROFS 30 /
Read-only file system /
#define EMLINK 31 /
Too many links /
#define EPIPE 32 /
Broken pipe /
#define EDOM 33 /
Math argument out of domain of func /
#define ERANGE 34 /
Math result not representable */

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值