什么是Linux系统IO?
Linux系统IO,指的是在Linux操作系统中进行的所有输入输出操作。这些操作可以通过不同的方式实现,包括系统I/O和标准I/O。
具体来说,系统I/O是Linux系统内核提供的API,主要用于处理底层的输入输出任务。例如,传统的访问方式是通过write()和read()两个系统调用实现的,通过read()函数读取文件到缓存区中,然后通过write()方法把缓存中的数据输出到网络端口。
另一方面,标准I/O是C语言在Linux操作系统下的API,主要用于处理应用程序的输入输出任务。它提供了一套丰富的库函数和系统调用,方便开发者进行文件读写操作。
以下是一些常用的系统IO:
- 打开文件:open()、creat()
- 关闭文件:close()
- 读取文件:read()
- 写入文件:write()
- 移动文件指针:lseek()
- 删除文件或目录:unlink()、rmdir()
- 创建目录:mkdir()
- 删除目录:rmdir()、rm()
- 重命名文件或目录:rename()
- 获取文件状态:stat()、fstat()
- 更改文件权限和时间戳:chmod()、chown()、utime()
本文主要介绍最常用的open()、close()、read()、write()、lseek()。
open()
Linux中的open()函数用于打开或创建一个文件,并返回一个文件描述符。它的定义如下:
#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);
参数说明:
- pathname:要打开或创建的文件的路径名。
- flags:表示文件打开方式和访问权限的标志位,如O_RDONLY(只读)、O_WRONLY(只写)、O_RDWR(读写)等。需要注意的是:flags是可以选择多种权限的,比如:O_RDWR | O_CREAT | O_APPEND(以读写的方式打开,以追加的方式打开文件,并且如果该文件不存在则创建该文件)。
- mode:当指定了O_CREAT标志时,表示需要使用文件的权限模式,如S_IRUSR(用户读)、S_IWUSR(用户写)等。比如上面我们设置了O_CREAT,那么在就必须设置mode,此时我们要设置对应的权限:比如:0666(设置为所有人可读写),但是需要注意的是默认 umask=0002,因此我们需要在文件open()前设置umask(0)。一个例子:
🌰
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main() { umask(0); int fd = open(FILE_NAME, O_WRONLY | O_CREAT | O_APPEND, 0666); close(fd); return 0; }
返回值:
成功时,返回一个非负整数,表示文件描述符;失败时,返回-1,并设置errno。
详细的操作:
close()
在Linux系统中,close()函数的主要功能是关闭一个已打开的文件描述符,以释放相应的系统资源。具体来说,close()函数会释放与该进程关联并由该进程拥有的文件上保留的所有记录锁,并使文件描述符不再引用任何文件,从而允许系统重用该文件描述符。
详细的操作:
write()
在Linux系统中,write()函数用于向文件中写入数据。其函数原型为:
#include <unistd.h> ssize_t write(int fd, const void *buf, size_t count);
其中,参数fd是文件描述符,表示要写入的文件;buf是一个指向要写入数据的缓冲区的指针;count是要写入的字节数。
当调用成功时,write()函数返回实际写入的字节数。如果返回的值与count相等,说明所有数据均已成功写入文件。如果返回的值小于count,则说明发生了错误或某些数据未能写入。
当发生错误时,write()函数会设置全局变量errno来指示具体的错误类型。例如:
- EACCES:访问被拒绝(通常是由于权限不足)。
- EPIPE:向一个已经关闭的管道或套接字发送数据。
- EAGAIN或EWOULDBLOCK:文件已被其他进程锁定或者当前没有可用的数据空间。
- EBADF:文件描述符无效。
- EINTR:系统中断,比如信号等导致了write()函数被提前终止。
- EIO:输入/输出错误,通常由硬件问题引起。
- ENOSPC:磁盘已满或者设备上没有足够的空间来存储数据。
需要注意的是,write()函数并不会将数据立即写入磁盘,而是将其缓存在内核中,等到满足一定的条件后才会真正写入磁盘。因此,如果想要确保数据被立即写入磁盘,可以使用fsync()函数或fdatasync()函数对文件进行同步操作。
🌰
#include<stdio.h> #include<sys/types.h> #include<unistd.h> #include<sys/stat.h> #include<fcntl.h> #include<string.h> #define FILE_NAME "1.txt" int main() { umask(0); int fd = open(FILE_NAME, O_WRONLY | O_CREAT | O_APPEND, 0666); char buf[1024]={0}; fgets(buf,sizeof(buf),stdin); int wd=write(fd,&buf,strlen(buf)-1);//strlen(buf)-1是为了去掉\n直接在后面接 printf("成功写入%d个数据\n",wd); close(fd); return 0; }
详细的操作:
read()
在Linux中,read()函数用于从文件描述符中读取数据。它通常与open()函数一起使用,以打开一个文件并获取文件描述符。
read()函数的原型如下:
#include <unistd.h> ssize_t read(int fd, void *buf, size_t count);
其中,fd是文件描述符,buf是一个指向缓冲区的指针,count是要读取的字节数。
read()函数返回实际读取的字节数,如果返回值小于请求的字节数,则表示已到达文件末尾或发生了错误。如果返回值为-1,则表示发生了错误。
🌰
#include<stdio.h> #include<sys/types.h> #include<unistd.h> #include<sys/stat.h> #include<fcntl.h> #include<string.h> #define FILE_NAME "1.txt" int main() { int fd=open(FILE_NAME,O_RDONLY); char buf[1024]={0}; int rd=read(fd,buf,sizeof(buf)); printf("读取:%d数据\n",rd); printf("%s\n",buf); close(fd); return 0; }
详细的操作:
lseek()
在Linux操作系统中,lseek()函数是一个关键的工具,用于改变文件的当前读写位置。这个函数主要应用在对文件进行随机访问的时候。
其函数原型为:
1.#include <sys/types.h> #include <unistd.h> off_t lseek (int fd, off_t offset, int whence);
其中,参数fd表示需要进行操作的文件描述符;offset表示偏移量,这是要移动的字节数,可正可负;whence则代表偏移起始位置,有以下三种选择:
- SEEK_SET: 从文件头部开始偏移offset个字节。
- SEEK_CUR: 从文件当前读写的指针位置开始,增加offset个字节的偏移量。
- SEEK_END: 文件偏移量设置为文件的大小加上偏移量字节。
值得注意的是,lseek()函数成功执行后会返回新的文件偏移量,如果操作失败则返回-1。通过这个函数,我们可以实现对文件的任意位置的读写操作,而不再局限于顺序读取或者写入数据。这对于管理大文件尤其有用,因为它允许我们直接跳转到所需的特定部分,而不是从头到尾按顺序处理文件内容。
🌰
#include<stdio.h> #include<sys/types.h> #include<unistd.h> #include<sys/stat.h> #include<fcntl.h> #include<string.h> #define FILE_NAME "1.txt" int main() { int fd=open(FILE_NAME,O_RDONLY); char buf[1024]={0}; for(int i=0;i<3;i++)//打印三次文件 { lseek(fd,0,SEEK_SET);//注意前下图中前部分注释掉该段,后半没注释 int rd=read(fd,buf,sizeof(buf)); printf("读取:%d数据\n",rd); printf("%s\n",buf); *buf='\0';//清空缓冲区操作 } close(fd); return 0; }
详细的操作:
感谢你耐心的看到这里ღ( ´・ᴗ・` )比心,如有哪里有错误请踢一脚作者o(╥﹏╥)o!