引言
上节课我们知道了,什么是文件的权限,以及如何去修改文件的权限,这节课,我们将带着大家一起使用Linux系统里面的API来操作文件,一起跟着笔者的步伐走起~
文章目录
纸上得来终觉浅,绝知此事要躬行 ——陆游
基本的文件操作函数介绍
在Linux系统编程中,我们先来看基本的API,理解基本的文件操作函数是非常重要的。
这节我们带着大家一起进入文件编程。
文件我们想到无非就三个操作,1、打开文件,2、操作文件内容,3、关闭文件
把大象装进冰箱?是的,就是这么简单。
于是乎,我们如何装进这个大象是我们学习的关键,用什么工具去打开冰箱(文件),如何把大象放进去(操作文件内容),放进去关冰箱(释放文件)
我们在Linux系统上,当然用的是Linux系统的API,来操作系统的文件了,Linux系统给我们提供哪些工具呢?
下面我列举了一些。可以先看一下,大致熟悉一下open
1、open()
:打开一个文件
open()
函数通常用于打开文件。其原型通常位于<fcntl.h>
头文件中
原型如下所示:
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
-
第一个原型是用于打开已存在文件的,第二个原型是用于创建新文件的。
-
pathname
参数是一个指向要打开的文件的路径名的指针。 -
flags
参数指定了打开文件的方式,比如只读、只写、读写等。常见的标志包括O_RDONLY
、O_WRONLY
、O_RDWR
等。 -
mode
参数用于指定新文件的权限,通常用于创建文件时。比如0644
表示文件所有者可读写,其他用户只读。 -
mode
是新创建文件的权限,通常与O_CREAT
标志一起使用。
2、close()
:关闭一个文件
close()
函数用于关闭一个先前打开的文件。下面是 close()
函数的原型和说明:
#include <unistd.h>
int close(int fd);
-
fd
是之前使用open()
或其他文件操作函数返回的文件描述符。通过关闭文件描述符,可以释放系统资源并确保文件的正确关闭。
3、read()
:读取文件内容
read()
函数用于从已打开文件中读取数据。下面是 read()
函数的原型和说明:
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
-
fd
是之前使用open()
打开文件返回的文件描述符。 -
buf
是一个指向存储读取数据的缓冲区的指针。 -
count
是要读取的字节数。 -
返回值:成功时返回实际读取的字节数,如果到达文件末尾则返回 0,出现错误时返回 -1。
4、write()
:写入文件内容
write()
函数用于向文件中写入数据。下面是 write()
函数的原型和说明:
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
-
fd
是之前使用open()
打开文件返回的文件描述符。 -
buf
是一个指向要写入的数据的缓冲区的指针。 -
count
是要写入的字节数。 -
返回值:成功时返回实际写入的字节数,出现错误时返回 -1。
5、lseek()
:在文件中定位
lseek()
函数在Linux系统中用于设置文件偏移量,即移动文件描述符的读写位置。下面是 lseek()
函数的原型和说明:
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
-
fd
是之前使用open()
打开文件返回的文件描述符。 -
offset
是要移动的偏移量,可以为正数、负数或零。 -
whence
用于指定偏移量的基准位置,可以是SEEK_SET
、SEEK_CUR
或SEEK_END
。具体含义如下:-
SEEK_SET
:从文件开头开始偏移。 -
SEEK_CUR
:从当前文件位置开始偏移。 -
SEEK_END
:从文件末尾开始偏移。
-
6、unlink()
:删除文件
unlink()
函数用于删除一个文件的目录项(文件名),并减少该文件的链接数。如果链接数变为零,则文件的数据块将被释放。下面是 unlink()
函数的原型和说明:
#include <unistd.h>
int unlink(const char *pathname);
pathname
是要删除的文件的路径名。
- 返回值:成功时返回 0,失败时返回 -1。
小节(man 手册)
就只有这些个操作函数吗?不,不是的,后面可能会遇到新的接口,接触自己认知以外的函数,我们遇到这些应该怎么办,不要慌,我告诉你怎么办。
在Linux系统编程当中,当我们使用了系统的接口,那么我们可以使用Linux自带的手册看接口如何使用,我们可以使用man
open来直接看linux对这些API的解释,以及他所需的头文件。比如:
bash man open
或者
bash man 2 open
总之,建议找不到函数的时候多看这个man手册,他里面都是有结构规律的,只需要找我们需要的东西就好,不用抠字眼一个一个去通读。
实操实例
实现功能:两个文件,demo1.c 以及 demo2.c
- demo1.c创建文件
- demo2.c删除文件
demo1.c创建文件
使用open创建一个文件,使用write向里面写入一段话“hello Linux,i im jiaju(Strange_Head) I’m coming.”,然后读取(read)全部的内容,打印到命令行,然后再次使用write尾部追加写入,“家驹很帅,梦想很近”,”-------------------------“,最后操作完成,使用close关闭文件.
注意,容易混的地方是lseek(将他理解为编辑文件时候的光标),初学者请慢慢理解下面的代码,附带详细注释。
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main()
{
//创建一个fd用作文件描述符
int fd = -1;
//我们直接创建文件,使用三个参数的open
//使用相对路径
//权限为可读可写O_RDWR,使用创建文件的宏O_CREAT
//文件权限,644
//int open(const char *pathname, int flags, mode_t mode);
fd = open("./家驹很帅.txt",O_RDWR | O_CREAT,644);
if(fd == -1) {
printf("文件创建或打开失败\n");
return -1;
}
//写入操作
//ssize_t write(int fd, const void *buf, size_t count);
char write_buffer[100];
memset(write_buffer,'\0',sizeof(write_buffer));
strncpy(write_buffer,"hello Linux,i im jiaju(Strange_Head) I’m coming.\n",sizeof("hello Linux,i im jiaju(Strange_Head) I’m coming.\n"));
write(fd,write_buffer,sizeof(write_buffer));
//使用lseek计算文件大小
//
//将lseek理解为光标,就像windows里面闪烁的光标
//如果通过sleek计算大小,我们先将光标置为文件开头,然后在移到末尾,中间偏移了多少字节既是文件大小
//off_t lseek(int fd, off_t offset, int whence);
lseek(fd,0,SEEK_SET);
int file_size = lseek(fd,0,SEEK_END);
lseek(fd,0,SEEK_SET); //得到文件大小需要再从头开始,因为后面read是从当前光标开始的
//读取操作
//ssize_t read(int fd, void *buf, size_t count);
char read_buffer[100];
memset(read_buffer,0,sizeof(read_buffer));
read(fd,read_buffer,sizeof(read_buffer));
//打印得到的字符串
printf("%s\n",read_buffer);
//注意,此时lseek的光标在文件末尾。
//
//我们接着追加内容
memset(write_buffer,'\0',sizeof(write_buffer));
strncpy(write_buffer,"\n家驹很帅,梦想很近\n",sizeof("\n家驹很帅,梦想很近\n"));
write(fd,write_buffer,sizeof(write_buffer));
//插入横杠
memset(write_buffer,'\0',sizeof(write_buffer));
strncpy(write_buffer,"\n-----------------------------------\n",sizeof("\n-----------------------------------\n"));
write(fd,write_buffer,sizeof(write_buffer));
//关闭文件
close(fd);
return 0;
}
demo2.c删除文件(手动制作rm命令)
直接调用unlink删除文件。
我们直接调用这个命令删除一个的固定文件,感觉不爽,既然要删除文件,如果我能指定就好了,直接做一个低配版的rm命令!
使用argc,argv的特性,轻松完成
#include <stdio.h>
#include <unistd.h>
int main(int argc,char **argv)
{
if(argc==2){
int i = 0;
for(i = 0;i < argc;i++){
printf("argv[%d]%s\n",i,argv[i]);
}
if(unlink(argv[1])<0){
printf("\n删除失败\n");
}
}else{
printf("参数错误\n");
}
return 0;
}
实例结果展示
调用demo1.c编译出的./creat,生成家驹很帅.txt
调用demo2.c编译出的./myrm, 删除生成的文件。
拓展
open系列和fopen系列有什么不同
fopen,fread,fwrite,flseek等等……
很多小伙伴可能知道,fopen可以打开文件,他和open有什么不一样呢,明明最终的结果是一样的。
答案:当然不一样,除了多了一个前缀f,还多了很多细节,我们来拓展一下。
open
函数是一个系统调用,而fopen
函数是C标准库提供的函数。
open
函数是低级别的函数,提供了更多的控制和自由度,可以指定文件的打开模式(读、写、追加等)、权限等。fopen
函数则是高级别函数,通常用于简单的文件操作,它提供了一种更简单的接口,隐藏了一些底层细节。
open
函数返回一个文件描述符(file descriptor),而fopen
函数返回一个FILE*
类型的指针。文件描述符是一个整数,用于标识已打开的文件,而FILE*
是一个指向FILE
结构体的指针,该结构体包含了文件流的信息。使用
open
函数打开文件后,通常需要使用read
和write
等系统调用来进行读写操作;而使用fopen
函数打开文件后,可以使用fprintf
、fscanf
等标准库函数来进行读写操作。
open
函数是Unix标准的一部分,而fopen
函数是C标准库的一部分。
fopen
有缓冲区,open
没有
无论是使用open,还是fopen,看个人喜好,已经代码编程习惯,我是倾向于open系列的。
结束
今天的学习就到这里了,唯手熟尔,我这里实现了一个rm功能,是不是可以自己想一想,实现一个cp自己的拷贝命令呢。