Linux下文件输入输出操作

标准库的IO接口

文件的打开方式

r:只读
r+:读写
w:只写
w+:读写
a:追加写(每次写入数据总是写入到文件末尾)
a+:追加读写
b:二进制操作

  • r+w+ 的区别:r+读写打开文件时若文件不存在则报错;w+读写打开文件时若不存在则创建,若存在则清空原有内容
  • a不仅仅是追加写,并且文件不存在还会创建新文件
  • 如果不指定b则默认文件是文本操作,加上b则认为是二进制操作;区别在于有时一个特殊字符占据了两个字节的内存(读取一个100字节大小的文件,文本操作最终读取出来的数据可能不到100个字节)

IO接口

fopen

FILE* fopen(char* filename,char* mode);		//filename--文件名称,mode--打开方式
  • 返回值:返回一个FILE*的文件流指针作为文件的操作句柄;失败则返回NULL
  • 打开文件之后 一定不能忘了close关闭文件

fread、fwrite

// buf--缓冲区,block_size--块大小,block_count--块个数,fp--文件流指针
size_t fread(char* buf,size_t block_size,size_t block_count,FILE* fp);
// data--数据首地址,block_size--块大小,block_count--块个数,fp--文件流指针
size_t fwrite(char* data,size_t block_size,size_t block_count,FILE* fp);
  • fread和fwrite操作的数据实际大小是块大小*块个数
  • 返回值:返回实际操作的块个数
  • 例:读取一个文件size=10,count=2;若文件大小足够则返回2,如文件大小只有16字节则返回1,因为第二块没读满
  • fread如果读到了文件末尾会返回0;
  • 若读取1000个字节,块个数为1,文件大小只有512字节,虽然读取了512字节的数据但也会返回0
  • fread/fwrite比较推荐块大小为1,因为块大小为1时块个数就是要操作的数据长度

fseek

int fseek(FILE* fp,long offset,int whence);
  • 将文件的读写指针从whence位置偏移offset个字节–跳转文件读写位置
  • 可偏移负数个字节(向前偏移),文件没有数据也可以跳转读写位置

fclose

int fclose(FILE* fp);
  • 关闭文件流指针,释放资源

Linux下系统调用IO接口

open
打开指定文件

int open(char* filename,int flag,mode_t mode);
  • filename:要打开的文件名称
  • flag:选项参数----文件的打开方式(必选项/可选项)
    • 必选项(只能选其一):O_RDONLY:只读;O_WRONLY:只写;O_RDWR:可读可写
    • 可选项:O_CREAT:文件存在则打开不存在则创建;O_EXCL与O_CREAT同时使用:文件存在则报错;O_TRUNC:打开文件的同时清空原有内容;O_APPEND:追加写(写入到末尾)
  • mode:权限;如果使用了O_CREAT有可能创建新文件,就一定要指定文件权限(八进制数字形式);若要操作文件,最好程序初始化时调用umask(0);将当前进程的umask值设置为0,这样在设置权限时就不需要再进行计算
  • 返回值:一个非负整数----文件描述符(文件在代码中的操作句柄),失败返回-1

write
向指定文件中写入指定长度的数据

ssize_t write(int fd,char* data,size_t len);
  • fd:open返回的文件描述符(文件操作句柄),通过这个fd指定要往哪个文件写入数据
  • data:要写入文件的数据的空间首地址
  • len:要写入的数据大小
  • 返回值:返回实际写入文件的数据字节长度;失败返回-1

read
从文件中读取指定长度的数据,放到buf中

ssize_t read(int fd,char* buf,size_t len);
  • fd:open返回的文件描述符
  • buf:从文件中读取数据放到哪块缓冲区中的首地址
  • len:想要读取的数据长度,这个len不能大于缓冲区大小
  • 返回值:返回实际读取到的数据字节长度;失败返回-1

lseek
跳转读写位置

off_t lseek(int fd,off_t offset,int whence);
/*例*/	lseek(fd,0,SEEK_END);	//返回的刚好为文件大小
  • fd:open返回的文件描述符
  • offset:偏移量
  • whence:从哪里开始偏移。SEEK_SET:从文件起始位置,SEEK_CUR:从文件当前读写位置,SEEK_END:文件末尾
  • 返回值:成功返回当前位置相对于起始位置的偏移量;失败返回-1

close
通过文件描述符关闭文件,释放资源

int close(int fd);
  • fd:文件描述符

文件描述符

概念:文件描述符其实是内核中一个文件描述信息数组的下标,通过这个下标可以在内核中找到相应的文件描述信息,通过描述信息可以实现文件操作

  • 文件描述符(操作文件的句柄)是一个非负整数
  • 文件描述符的分配规则:最小未使用
  • 一个进程中默认会打开三个文件:标准输入:0,标准输出:1,标准错误:2
  • 为什么一个文件在不操作后一定要关闭?
    释放资源,文件描述符是有限的。若不关闭文件,描述符用光,进程中就无法打开新文件了

文件描述符与文件流指针的关系

  • 文件描述符:文件描述信息数组的下标,是一个非负整数,是系统调用的IO接口
  • 文件流指针FILE是一个结构体(typedef struct _IO_FILE FILE),有一个成员就是文件描述符,是库函数IO接口的操作句柄
  • 我们通常说的缓冲区实际上是文件流指针结构体中的缓冲区,这个缓冲区通常被称之为用户态缓冲区

缓冲区

  • 向文件写入数据,并不会直接写入文件,而是写入缓冲区,刷新缓冲区的时候才会写入文件
  • 系统调用接口是直接将数据写入文件的,系统调用接口没有缓冲区,只有库函数才有缓冲区
  • exit退出会刷新缓冲区/_exit退出时不会刷新缓冲区

重定向

改变描述符所指向的文件描述信息,改变当前描述符所操作的文件,最终改变数据的流向。实际是描述符的重定向,将数据不再写入原本的文件,而是写入新的指定文件中

int dup2(int oldfd,int newfd)	//描述符重定向函数
  • 让newfd这个描述符也指向oldfd所指向的文件,这时候oldfd和newfd都能操作oldfd所指向的文件

文件系统

文件系统就是磁盘上管理文件的系统。linux下ext2文件系统将磁盘分为五个区域:超级块inode bitmap1data bitmapinodedata

文件的存储:通过超级块找到inode位图/数据块位图,通过数据块位图快速找到空闲的磁盘块存储文件数据,通过inode位图快速找到空闲的inode节点,存储文件的元信息

  • 目录项:文件名+inod节点号。Linux下文件的数据和文件的名称是分离的,文件的数据以及inode信息存储完毕之后,将目录项存储到父目录文件中

文件的获取:通过文件名到父目录文件中找到文件对应的目录项,得到文件的inode节点号,在磁盘超级块中找到inode节点区域,根据inode节点号,快速找到inode节点,得到数据存储的磁盘块号(数据块位置),进而获取到文件数据

软链接文件、硬链接文件

软链接文件/硬链接文件:给一个源文件创建一个软链接文件/硬链接文件,就可以通过被创建出来的软链接/硬链接文件来操作源文件

ln test.txt test.hard		// 为源文件创建一个硬链接文件
ln -s test.txt test.soft	// 为源文件创建一个软链接文件

软连接文件和硬链接文件的区别:

软连接文件硬链接文件
软链接文件是独立的文件,有自己的inode号,里面保存着源文件的路径,通过路径访问源文件数据硬链接文件是一个文件的目录项(只是源文件的别名),和源文件共用一个inode号,通过inode节点访问源文件数据
删除源文件,软链接文件失效删除源文件, 硬链接文件只是链接数-12 3,依然可以访问源文件数据
软链接文件可以对目录创建硬链接文件不可以对目录创建
软链接文件可以跨分区创建硬链接文件不可以跨分区创建

库的打包与使用

库文件:打包了一堆实现了常用功能的代码文件

打包流程

  1. 将各个高级语言代码(.c文件等)编译汇编成为机器指令。例:gcc -c child.c -o child.o;生成动态库时最好加上-fPIC产生位置无关的代码:gcc -c -fPIC child.c -o child.o
  2. 将所有的.o文件以及库文件打包生成自己的库文件
    动态库的打包:gcc -shared child.o -o libmychild.so;动态库的命名方式:lib***.so
    静态库的打包:ar -cr libmychild.a child.o;静态库命名方式:lib***.a

库的使用

生成可执行程序时链接使用

  • 将库文件放到指定路径下:/usr/lib64或/usr/lib
  • 设置链接库的搜索路径环境变量,将当前库文件所在路径添加进去:export LIBRARY_PATH=$LIBRARY_PATH:.
  • 使用gcc -L选项指定链接库的搜索路径:gcc main.c -o main -L. -lmychild

运行可执行程序时加载使用:仅仅针对动态库(只有动态库才会在运行时加载库文件)

  • 必须将库文件放到指定路径下:/usr/lib64或/usr/lib
  • 设置链接库的加载路径环境变量,将当前库文件所在路径添加进去:export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.

  1. 位图:一连串的二进制比特位,用来做一种数据标记 ↩︎

  2. 链接数:一个inode节点对应有几个目录项 ↩︎

  3. 删除一个文件,文件并不会立即被删除,而是删除了目录项信息,inode中的链接数-1,只有链接数为0时,才会真正删除文件 ↩︎

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值