linux的文件系统是一个广义的文件系统,能够认为linux系统对任何设备和对象的操做都是等价于对文件的操做。linux
linux系统对全部可操做对象进行了高度的抽象,将其概括为这么几类:网络
1. 普通文件:就是狭义概念上的存储在磁盘中的文件,是纯粹的存储数据的文件,例如文本文件,图片文件,可执行文件等;数据结构
2. 字符设备文件:一般指输入输出终端,键盘,串口等,一般能够用操做文件的方式来操做字符设备文件,由于对这类设备的读写实际上是读写的字符流;架构
3. 块设备文件:有硬盘,软盘和RAM等,块设备文件一般公国内存缓冲区读写数据,支持块数据读取和随机读取,读写性能更好;app
4. socket文件:网络通讯的文件描述符,支持像操做普通文件同样操做网络数据的读写;异步
linux提供了虚拟文件系统架构,要求全部设备都提供一致的文件操做接口,方便用户像操做文件同样操做全部设备,所以能够说linux系统下,一切操做的都是文件。socket
文件描述符函数
文件描述符是对一个操做文件的抽象标识,它被用户空间和内核空间的枢纽共同使用。当用户空间对一个文件描述符进行操做时,例如对一个文件描述符进行操做时,当内核进行系统调用时,将根据该文件描述符找到对应的真实设备进行操做,并将结果返回用户空间。性能
文件描述符一般是一个整数标识,所以它根据系统不一样,有一个上线值(一般是0-OPNE_MAX)。因此,咱们在使用完一个文件后,应该尽快释放它(一般调用close函数)。ui
1. 打开文件和建立文件
头文件:sys/types.h sys/stat.h fcntl.h
int open(const char* filepath, int flags);
int create(const char* filepath, int flags, mode_t mode);
打开和建立成功返回一个文件描述符,失败返回-1。一般filepath的字符长度也会有限制,若是超出长度会被截断。
flags的选项:
O_RDONLY (0 只读)
O_WRONLY (1 只写)
O_RDWR (2 读写)
O_APPEND (写操做追加到末尾)
O_CREATE (若是文件不存在,建立一个,须要mode来设置权限)
O_EXCL (查看文件是否存在。若是同时指定O_CREATE,而且文件已经存在,会返回错误)
O_TRUNC (将文件长度截断为0)
mode的选项:
S_IRWXU 用户有读写和执行权限
S_IRUSR 用户有读权限
S_IWUSR 用户有写权限
S_IXUSR 用户有执行权限
S_IRWXG 组用户有读写和执行的权限
S_IRGRP 组用户有读权限
S_IWGRP 组用户有写权限
S_IXGRP 组用户有执行权限
S_IRWXO 其余用户有读写和执行权限
S_IROTH 其余用户有读权限
S_IWOTH 其余用户有写权限
S_IXOTH 其余用户有执行权限
对文件的操做默认都是阻塞的,即必须等到文件操做返回才能继续。
2. 关闭文件
int close(int fd);
若是成功返回0,失败返回-1。在关闭文件后,系统能够再次使用该文件描述符,若是使用后不关闭,进程也会在退出时关闭全部打开的文件描述符,可是可能形成文件描述符不够用的状况,致使没法再打开新的文件。
3. 读取文件
头文件:unistd.h
ssize_t read(int fd, void* buf, size_t count);
从文件fd读取count字节的字节流并存到buf指向的内存地址中。读取成功返回读取成功的字节数,若是返回0标识读取到文件末尾,读取失败返回-1。ssize_t的定义是依赖平台,多是long或者int。实际状况返回的字节数可能小于count指定的大小,表示没法读取到count大小的字节,已经将文件中当前剩余的全部字节所有读取出来。
4. 写文件
头文件:unistd.h
ssize_t write(int fd, const void* buf, size_t count);
向文件fd中写入指定count大小的数据,数据来自buf指向的内存地中的字节流。若是成功返回写入成功的字节数,失败返回-1。
5. 文件偏移
头文件:sys/types.h unistd.h
off_t lseek(int fd, off_t offset, int whence);
文件偏移量:文件操做的当前位置,全部文件操做都是从文件偏移量开始的。若是在打开文件的时候,指定了O_APPEND,文件偏移量就是文件的长度,即末尾处,不然偏移量为0,即文件起始位置。
lseek函数能够更新文件fd的偏移量,offset可为整数或负数,表示相对whence的偏移大小。
whence选项:
SEEK_SET:文件的开始位置;
SEEK_CUR:文件的当前位置;
SEEK_END:文件的结尾位置;
若是函数执行成功返回偏移量的值,可能为负数,失败返回-1。
当向文件写数据时,若是使用lseek设置偏移量超出了文件大小,当继续向文件写入数据时,中间的空白字节会用'\0'填充。
6. 获取文件状态
头文件 sys/types.h sys/stat.h unistd.h
int stat(const char* path, struct stat* buf);
int fstat(int fd, struct stat* buf);
int lstat(const char* path, struct stat* buf);
若是获取成功返回0,失败返回-1。文件状态的数据写入buf指向的数据结构中。
7. 文件空间映射
头文件:sys/mman.h
void* mmap(void* start, size_t length, int prot, int flags, int fd, off_t offset);
该函数将文件映射到内存中,而后就能够采用内存操做,没必要再使用read和write函数,性能更好。
start:内存的开始地址,可是一般不须要指定,设置为NULL,表示由系统决定映射的地址,在返回值中体现;
length:表示映射的地址长度,即从文件映射到内存中的数据大小;
prot:映射区域的保护方式,能够由多个值进行组合;
PROT_EXEC 可执行区域
PROT_READ 可读取区域
PROT_WRITE 可写区域
flags:设定映射区域的类型,选项和对映射区域是否能够操做,能够由多个值进行组合;
MAP_FIXED 若是参数start指定的地址没法创建映射,映射会失败,一般不指定该值,将start设置为NULL,由系统选定映射地址;
MAP_SHARED:映射区域是多进程共享的,对映射区域的操做都会影响原来的文件;
MAP_PRIVATE:映射区域的写操做都会产生一个副本,而且写操做不会影响原来的文件;
MAP_DENYWRITE:对文件的写入操做被禁止,只能经过对映射区域的操做来实现对文件的操做;
MAP_LOCKED:将映射区域锁定,不会被虚拟内存重置;
int munmap(void* start, size_t length);
取消文件映射,一般在映射区域操做完成后调用,而后关闭文件;
1 int fd = open("leo.txt", O_RDWR | O_CREAT, S_IRWXU); 2 if (fd == -1) { 3 printf("create file failed."); 4 } 5 else { 6 char buf[] = "leo is me!"; 7 write(fd, buf, strlen(buf)); 8 9 char* ptr = (char*)mmap(NULL, strlen(buf), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 10 if ((char*)-1 == ptr) { 11 printf("mmap failed."); 12 } 13 else { 14 memcpy(ptr, "123", 3); 15 munmap(ptr, strlen(buf)); 16 close(fd); 17 } 18 }
8. 文件属性操做
头文件:unistd.h fcntl.h
int fcntl(int fd, int cmd);
int fcntl(int fd, int cmd, long arg);
int fcntl(int fd, int cmd, struct flock* lock);
对文件的属性进行修改,失败返回-1。
fcntl的功能:
复制文件描述符:cmd = F_DUPFD,返回值是新的文件描述符。新的文件描述符是大于或等于第三个参数的还没有使用的文件描述符中的最小值;
获取或设置文件描述符:cmd = F_GETFD/F_SETFD;
获取或设置文件状态值:cmd = F_GETFL/F_SETFL;
文件状态值:
O_RDONLY 只读
O_WRONLY 只写
O_RDWR 读写
O_APPEND 将写入添加到末尾
O_NONBLOCK 非阻塞方式
O_SYNC 异步方式
O_ASYNC 同步方式
正确得到O_RDONLY,O_WRONLY和O_RDWR标志位的方法是和O_ACCMODE进行与操做才能得到;
int fd = open("leo.txt", O_RDWR | O_CREAT, S_IRWXU);
if (fd == -1) {
printf("create file failed.");
}
else {
int flags = fcntl(fd, F_GETFL, 0);
if (flags < 0) {
printf("get flags failed123333.");
}
else {
int accmode = flags & O_ACCMODE;
if (accmode == O_RDONLY) {
printf("file only read. \n");
}
else if (accmode == O_WRONLY) {
printf("file only write \n");
}
else if (accmode == O_RDWR) {
printf("file can be read and write. \n");
}
else
{
printf("accmode invalid. \n");
}
flags |= O_APPEND;
int result = fcntl(fd, F_SETFL, &flags);
if (result < 0) {
printf("set file flag failed. \n");
}
int newflags = fcntl(fd, F_GETFL, 0);
if (newflags & O_APPEND) {
printf("file append. \n");
}
if (newflags & O_NONBLOCK) {
printf("file non block. \n");
}
close(fd);
}
}
获取或设置文件信号的发送对象:cmd = F_GETTOWN/F_SETTOWN/F_GETSIG/F_SETSIG;
int uid = fcntl(fd, F_GETOWN); // 获取接受信号SIGIO和SIGURG的进程id
int uid = fcntl(fd, F_SETOWN, 10000); // 将接受信号SIGIO和SIGURG的进程设置为id为10000的进程
获取或设置记录锁:cmd = F_GETLK/F_SETLK/F_SETLKW;
获取或设置文件租约:cmd = F_GETLEASE/F_SETLEASE;
9. 文件输入输出控制
头文件:sys/iotl.h
int ioctl(int device, int request, ...);
经过向设备发送命令来控制设备,失败返回-1。device为一个打开的设备号,其余参数根据设备驱动程序来决定。
#include "stdlib.h" #include "stdio.h" #include <unistd.h> #include <fcntl.h> #include <linux/cdrom.h> #include <sys/ioctl.h> int main(void) {int fd = open("/dev/cdrom", O_RDONLY | O_NONBLOCK); if (fd > 0) { if (!ioctl(fd, CDROMEJECT, NULL)) { printf("ok \n"); } else { printf("fail \n"); } } getchar(); return 0; }