在Linux操做系统中,为了提升系统的稳定性,保证内核的安全,程序运行时的内存空间被分为了用户空间和内核空间。普通应用程序工做在用户空间,不能直接访问内核空间。它们须要使用Linux系统提供给用户的一些"特殊接口" - 系统调用来安全地访问内核空间。linux
要对文件进行读写就须要使用Linux系统提供的一些系统调用。在这篇文章中我主要介绍 open()
, write()
, read()
, lseek()
和 close()
等函数,在下文中我会详细讲解这些函数的使用。git
在Linux系统中,一切均可以被看做是文件,这包括:普通文件、目录文件、连接文件和设备文件。要访问文件,必须使用文件描述符。文件描述符是一个非负的整数,它是系统中被打开文件的索引。当打开或者建立一个文件时,内核会返回一个文件描述符;当须要读写文件时,也须要将相应的文件描述符做为参数传给读写函数。程序启动时,默认有3个文件描述符:github
文件描述符 | 宏 | 说明 |
---|---|---|
0 | STDIN_FILENO | 标准输入 |
1 | STDOUT_FILENO | 标准输出 |
2 | STDERR_FILENO | 标准错误输出 |
若是此时建立或打开一个文件,这个文件的文件描述符就是3.小程序
open()
函数用于打开或者建立文件。其在打开或者建立文件时能够指定文件的属性及用户的权限等各类参数。要使用 open()
函数,须要包含 #include <sys/stat.h>
和 #include <fcntl.h>
这两个头文件。下面是函数的说明:安全
int open(const char *path, int oflag, [mode_t mode]); args: const char *path: 文件路径,能够是绝对,也能够是相对路径 int oflag : 文件打开的方式 - O_RDONLY 只读打开 - O_WRONLY 只写打开 - O_RDWR 可读可写打开 以上3种必选一个,如下4种能够任意选择 - O_APPEND 追加打开,所写数据附加到文件末 - O_CREAT 若此文件不存在则建立它 - O_EXCL 若文件存在则报错返回 - O_TRUNC 若是文件已存在,而且以只写或可读可写方式打开,则将其长度截断为0字节 [mode_t mode] : 文件权限,只有在建立文件时须要使用 return: 文件描述符,非负整数是成功,-1是失败
在 open()
函数中,文件的打开方式不止上面的几种,这里只列举了经常使用的7种。注意,新建文件的权限不是直接等于 mode
的值,而是等于 mode & ~uname
。函数
当文件打开后,咱们就能够向该文件写数据了。在Linux系统中,用 write()
向打开的文件写入数据,要使用这个函数,须要包含 #include <unistd.h>
。下面是函数的说明:this
ssize_t write(int fildes, const void *buf, size_t nbyte); args: int fildes : 写入文件的文件描述符 const void *buf: 写入数据在内存空间存储的地址 size_t nbyte : 期待写入数据的最大字节数 return: 文件实际写入的字节数,非负整数是成功,-1是失败(磁盘已满或者超出该文件的长度等)
注意函数的返回类型是 ssize_t
。 ssize_t
同 size_t
相似,只是 ssize_t
表示有符号数。想了解更多 size_t
和 ssize_t
的区别请看这篇文章。spa
同写文件相似,要使用读文件函数 read()
,须要包含 #include <unistd.h>
。下面是函数的说明:操作系统
ssize_t read(int fildes, void *buf, size_t nbyte); args: int fildes : 读取文件的文件描述符 void *buf : 读取数据在内存空间存储的地址 size_t nbyte: 期待读取数据的最大字节数 return: 文件实际读取的字节数,非负整数是成功,-1是失败
同 write()
同样, read()
函数的返回类型也是 ssize_t
。.net
在每一个打开的文件中都有一个文件的偏移量,文件的偏移量会根据文件的读写而改变位置。咱们能够经过 lseek()
函数来调整文件的偏移量。默认状况下,新打开文件的文件偏移量在文件的开始。同 write()
和 read()
函数相似,要使用这个函数,须要包含 #include <unistd.h>
。下面是函数的说明:
off_t lseek(int fildes, off_t offset, int whence); args: int fildes : 修改文件的文件描述符 off_t offset: 文件偏移量移动的距离 int whence : 文件偏移量的基址 - SEEK_SET 文件开始处 - SEEK_CUR 文件当前位置 - SEEK_END 文件结束处 return: 当前文件指针的位置,非负整数是成功,-1是失败
off_t
同 ssize_t
相似,都是有符号数。
当文件再也不被使用时,能够调用 close()
函数来关闭被打开的文件。
除了用 close()
显示地关闭文件外,经过结束进程也能隐式地关闭被该进程打开的全部文件。要使用该函数,须要包含 #include <unistd.h>
。下面是函数的说明:
int close(int fildes); args: int fildes: 要关闭文件的文件描述符 return: 文件关闭状态,0是成功,-1是失败
这是一个简单的文件基本操做实例。在这个例子中,程序分两次将内存中的字符串写入文件,而后又将文件内容读回内存空间。
#include <stdio.h> #include <string.h> #include <unistd.h> #include <fcntl.h> /** * This is a simple example for using open(), write(), read(), lseek() and close(). */ int main(int argc, char *argv[]) { int fd; ssize_t wr_size, rd_size; char buffer[128]; char string_1[30], string_2[30] = "This is the second line!\n"; char *path = "./file_io.log"; fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 511); if (fd < 0) { printf("File create fail...\n"); return -1; } else { printf("File create success...\n"); } /* write the first line to file_io.log */ strcpy(string_1, "This is a demo for file_io!\n"); wr_size = write(fd, string_1, strlen(string_1)); if (wr_size < 0) { printf("File write 1 fail...\n"); printf("wr_size = %d\n", wr_size); return -1; } else { printf("File write 1 success...\n"); printf("wr_size = %d\n", wr_size); } /* write the second line to file_io.log * in this case, we only write 10 bytes data from string_2 to file. */ wr_size = write(fd, string_2, 10); /* add "\0"(not '\0'!!) to the end of the second line */ wr_size = write(fd, "\0", 1); if (wr_size < 0) { printf("File write 2 fail...\n"); printf("wr_size = %d\n", wr_size); return -1; } else { printf("File write 2 success...\n"); printf("wr_size = %d\n", wr_size); } /* decrease current file offset by 20 bytes */ lseek(fd, -20, SEEK_CUR); rd_size = read(fd, buffer, 100); if (rd_size < 0) { printf("File read_1 fail...\n"); printf("rd_size = %d\n", rd_size); return -1; } else { printf("File read_1 success...\n"); printf("rd_size = %d,\nbuffer = %s\n", rd_size, buffer); } close(fd); return 0; }
编译并运行该程序,程序和文件输出结果以下:
对于上面的例子,有几点须要注意:
1) 在40行处, wr_size = write(fd, string_2, 10);
咱们写入的字节数是小于 string_2
中的字节数的。若是想要写入的字节数大于 string_2
中的字节数,那 string_2
外的字节也会写入文件(这些额外的字节不是咱们但愿要的)。好比咱们将40行改成 wr_size = write(fd, string_2, 100);
其输出结果以下:
2)若是注释掉53行,则读出的字节数为0,由于此时文件的偏移量处于文件的尾部。
这是一个模仿Linux cp指令的小程序,这里并无考虑效率,也没有考虑特殊状况,只是简单地实现其功能。
#include <stdio.h> #include <string.h> #include <unistd.h> #include <fcntl.h> /* * This a simple version of cp command. */ int main(int argc, char *argv[]) { int fd1, fd2; ssize_t rd_size; char buffer[128]; if (argc != 3) { printf("You should enter enter 2 parameters\n"); return -1; } fd1 = open(argv[1], O_RDONLY); if (fd1 < 0) { printf("File %d does not exist...\n", fd1); return -1; } fd2 = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 511); if (fd2 < 0) { printf("File %d open fail...\n", fd2); return -1; } while(read(fd1, buffer, 1)) write(fd2, buffer, 1); close(fd1); close(fd2); return 0; }
编译并运行该程序,程序输出结果以下:
这篇文章主要介绍了如何使用文件IO的系统调用函数对文件进行操做,文中出现的代码均可在个人github上找到。
若是以为本文对你有帮助,请多多点赞支持,谢谢!