前言
对于文件IO来说,一切都是围绕文件描述符来进行的,在Linux系统中所有打开的文件都是一个对应的文件描述符。
文件描述符的本质是一个非负整数,当我们打开一个文件时,系统会给我们分配一个文件描述符。
当我们对一个文件做读写操作的时候,我们使用open函数的时候返回的就是这个文件的文件描述符,我们后续对文件的操作例如read和write都需要使用这个参数。
完成目标:
在windows上编程和Linux上的文件操作有所不同(如果需要学习windows上的文件操作编程可以跳转到这里:C/C++文件读取操作),本文主要是熟悉Linux上的文件操作的接口使用和相关文档的翻译。
一、工程的创建
1、目录结构
2、Makefile
object = *.o CC = gcc main:$(object) $(CC) $(object) -o main rm *.o file main %.o:%.c $(CC) -c $< clean: rm *.o rm main
这里复制需要注意一下需要将复制过去的空格替换成TAB
二、文件的操作
1.创建、打开、关闭文件:open、close、creat
如需要查看函数的完整说明使用以下命令查看详细的说明;
man open man close
下面是打开文件的函数接口以及使用该接口需要包含的头文件
// 使用系列操作需要包含得头文件 #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> // 文件操作的接口函数:我们常用的是open int open(const char *pathname, int flags); // 如果没有创建文件得权限使用该打开方式 int open(const char *pathname, int flags, mode_t mode);// 如果打开文件发现没有得情况需要创建选项这里就需要填写mode权限
const char* pathname传入的是文件名的字符串地址
flags表示文件的打开方式,如下表
参数 | 含义 |
O_CREAT | 必要时创建文件 |
O_TRUNC | 删除全部现有数据 |
O_APPEND | 维持现有数据,保存到其后面 |
O_RDONLY | 只读打开 |
O_WRONLY | 只写打开 |
O_RDWR | 读写打开 |
第二个函数还提供一个mode_t的参数该参数是表示创建文件的权限设置,这里类似chmod指令,在commod下使用ls -al 或则 ll指令可以查看文件权限
-rw-rw-r-- 1 stylle stylle 291 May 24 10:36 file.c -rwxrwxr-x 1 stylle stylle 8384 May 24 10:16 main -rw-rw-r-- 1 stylle stylle 129 May 24 10:03 Makefile
r表示可读 -4
w表示可写 - 2
x表示可执行 -1
所以我们常用到得chmod 777 就表示将该文件赋予可读可写可执行得权限;我们在操作完文件过后一定要释放文件,所以我们open过后一定要跟close函数,就如同malloc和free一样;
#include <unistd.h> int close(int fd); // 直接传入我们刚刚open函数返回的文件描述符
完整的使用用例
#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("file_tmp.c", O_CREAT | O_RDWR,0666); if(fd < 0) { perror("open file error\r\n"); } else{ printf("fd = %d\r\n",fd); close(fd); } return 0; }
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int creat(const char *pathname, mode_t mode);
pathname为创建文件的名称
mode表示创建文件的权限
返回的参数为创建的文件描述符,如果小于0表示文件创建失败,下面是程序演示
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> int main(int argc, char **argv) { int fd; if(argc < 2) { perror("plese input creat filename\r\n"); exit(0); } int ret = creat(argv[1], 0666); if(ret < 0) { perror("creat file error\r\n"); exit(0); } printf("creat file %s success\r\n",argv[1]); return 0; }
2.读取、写入文件:read、write
然后我们开始向文件中写入内容然后从中读取出来,这里我们需要使用到write和read,然后我们查看函数需要传入的参数
#include <unistd.h> ssize_t write(int fd, const void *buf, size_t count); ssize_t read(int fd, void *buf, size_t count);
write
fd表示文件描述符,这里填写我们open函数返回的fd就可以了
buf表示要写入文件的字符串
count表示要写入字符的个数
read
fd表示文件描述符,这里填写我们open函数返回的fd就可以了
buf表示接收读取到的字符串
count表示要读取的字符个数
然后我们来实验一下
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <string.h> int main(int argc, char **argv) { int fd; char read_str[15]; int ret = 0; fd = open("tmp.txt", O_CREAT | O_RDWR,0666); if(fd < 0) { perror("open file error\r\n"); exit(0); } ret = write(fd, "hello world", strlen("hello world")+1);// +1是strlen未包含‘\0’的长度 if(ret < 0) { perror("write error\r\n"); } close(fd); fd = open("tmp.txt", O_RDONLY); if(fd < 0) { perror("open read only file error\r\n"); exit(0); } ret = read(fd, read_str, ret); close(fd); if(ret < 0) { perror("read error\r\n"); } else { printf("read_num = %d read:%s\r\n",ret,read_str); } return 0; }
3.文件定位:lseek
下面是打开文件的函数接口以及使用该接口需要包含的头文件
#include <sys/types.h> #include <unistd.h> off_t lseek(int fd, off_t offset, int whence);
fd 文件描述符
offset 文件指针位移位置如果为正整数表示向后位移如果为负整数表示向前位移
whence 一共有三个参数SEEK_SET、SEEK_CUR、SEEK_END分别表示从文件头、当前位置、文件尾开始位移
返回值为当前位移指针的位置,如果位移出错返回-1,下面来个小实验
#include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <stdlib.h> int main(int argc, char **argv) { int fd; int ret; char read_str[10]; fd = open("a.txt", O_RDONLY); if(fd < 0) { perror("open error"); exit(0); } // a.txt: "hello stylle" ret = read(fd, read_str, 5);// read "hello" if(ret < 0) { perror("read error"); } else { ret = lseek(fd, 0, SEEK_CUR);// return cur file addr read_str[5] = '\0'; printf("read %d:%s\n",ret, read_str); ret = lseek(fd, 0, SEEK_END); printf("file size:%d\n",ret); lseek(fd, -7, SEEK_CUR);// '\0' memset(read_str, 0, 10); ret = read(fd, read_str, 6); if(ret > 0) { printf("read 6 digits:%s\n",read_str); } close(fd); } return 0; }
最后
本章需要注意的点:
1、写入文件后不能马上读取需要重新打开读取
2、上述的内容并没有十分完整,完整函数的用法和原型可以使用man 函数名称 进行查阅