文件类型说明
Linux系统中把一切都看做文件,Linux有7中类型文件:普通文件、目录文件、符号(link)链接、字符 (character)设备文件、块(block)设备文件、套接字(socket)、文件管道(pipe)文件。其中文件、目录、符号链接会占用磁盘空间来存储,
文件类型 | 文件类型标识符 |
- | 普通文件 |
d | 目录文件 |
l | 符号链接文件 |
c | 字符设备文件 |
b | 块设备文件 |
p | 管道文件 |
s | 套接字socket |
而块设备、字符设备、套接字、管道是伪文件,并不占用磁盘空间。
文件描述符介绍
文件描述符(file descriptor, fd)是Linux内核为了高效管理已被打开的文件所创建的索引,其是一个非负整数(通常是小 整数),用于指代被打开的文件,所有执行I/O操作的系统调用都通过文件描述符来进行的。程序在开始运行时,系统会自动打开三个 文件描述符,0是标准输入,1是标准输出,2是标准错误。POSIX标准要求每次打开文件时(含socket)必须使用当前进程 中最小可用的文件描述符号码,因此第一次打开的文件描述符一定是3.
文件描述符 | 用途 | POSIX文件描述符 | 标准/IO文件流 |
0 | 标准输入 | STDIN_FILENO | stdin |
1 | 标准输出 | STDOUT_FILENO | stdout |
2 | 标准出错 | STDERR_FILENO | stderr |
我们可以通过一个代码例程来了解文件描述符:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#define MSG_STR "Hello World\n"
int main(int main, char *argv[])
{
printf("%s", MSG_STR);
fputs(MSG_STR, stdout);
write(STDOUT_FILENO, MSG_STR, strlen(MSG_STR));
return 0;
}
输出结果如下图所示
文件IO操作函数
open()
函数原型
int open(const char *path, int oflag, .../*mode_t mode*/);
open()系统调用用来打开一个文件,并返回一个文件描述符(file description), 并且该文件描述符是当前进程最小、未使用的 文件描述符数值。
参数: path: 要打开的文件、设备的路径
oflag: 由多个选项进行“或”运算构造oflag参数 。
必选: O_RDONLY (只读)、 O_WRONLY(只写)、 O_RDWR(读写)
可选: O_APPEND 每次写时都追加到文件的尾端。
O_CREAT 文件不存在则创建它,使用该选项需要第三个参数mode
O_TRUNC 如果文件存在,而且为只写或读写成功打开,则将其长度截取为0;
O_NONBLOCK 如果path是一个FIFO、块设备、字符特殊文件则此选项为文件的本次打开和后续的I/O操作 设置非阻塞模式方式。O_EXEC、O_SEARCH、O_CLOEXEC、O_NOCTTY....
mode:oflag带O_CREAT选项时可以用来创建文件,这时必须带该参数用来指定创建文件的权限模式,如066,否则不需要。
实例代码
int fd;
fd = open(“text.txt”, O_RDWR|O_CREAT|O_TRUNC, 0666);
fd = open(“text.txt”, O_WRONLY|O_APPEND);
creat()
int creat(const char *path, mode_t mode);
此函数用来创建一个新的文件并返回其fd,它等价于open(path,O_WRONLY|O_CREAT|O_TRUNC,mode);
代码示例
int fd;
fd=creat(“text.txt”, 0644);
close()
函数原型
int close(int fd);
该函数用来关闭一个打开的文件描述符,关闭一个文件时还会释放加在该文件上的所有记录锁,当一个进程终止时,内核将会自动关闭它所有打开的文件。
read()
函数原型
ssize_t read(int fd, void *buf, size_t nbytes);
read()函数用来从打开的文件描述符对应的文件中读取数据放到buf指向的内存空间中去,最多不要超过nbytes个字节,这里的nbytes一般是buf剩余的空间大小。如read成功,则返回实际读到的字节数(由nbytes或读到文件尾决定,其中EOF宏用 来判断是否到了文件尾),如果返回值小于0则表示出错,如尝试读一个没有权限读的文件时就会抛错。
代码示例
int rv = 0;
rv = read(fd, buf, strlen(buf)); //如果成功,rv 值为read读到实际字节数;如果read失败,则rv <0;
write()
函数原型
ssize_t write(int fd, const void *buf, size_t nbytes);
write()函数用来往打开的文件描述符fd指向的文件中写入buf指向的数据,其中nbytes指定要写入的数据大小。如果返回值 <0则说明写入出错,譬如尝试往一个只读的文件中写入则会抛错,错误的原因系统会保存到errno变量中去。如果>0则为实 际写入的数据大小。
代码示例
int rv = -1;
rv = write(fd, buf, strlen(buf)); //如果write成功,则rv的值为实际写到buf中的字节数,出错则rv的值小于 0;
lseek()
函数原型
off_t lseek(int fd, off_t offset, int whence);
我们在从文件里读出内容,或往文件写如内容的时候都有一个起始地址,这个起始地址就是当前文件偏移量,当我们对文件 进行读写的时候都会使文件偏移量往后偏移。这点就类似于我们打开记事本开始编辑文本时的光标,我们读或写入时从光标 所在位置开始读写,每读写一个字节都会使光标往后偏移。通过lseek()这个函数我们可以调整文件偏移量的地址。 其中 whence 可以是以下三个值:
whence | 位置 |
SEEK_SET | 文件头 |
SEEK_CUR | 当前位置 |
SEEK_END | 文件尾 |
而offset就是相对于whence的偏移量,比如:
lseek(fd, 0, SEEK_SET); 将文件偏移量设置到了文件开始的第一个字节上;
lseek(fd, 0, SEEK_END); 将文件偏移量设置到了文件最后一个字节上;
lseek(fd, -1, SEEK_END); 将文件偏移量设置到了文件的倒数第一个字节上;
dup()和dup2()
函数原型
int dup(int fd);
int dup2(int fd, int fd2);
这两个函数都可以用来复制一个新的文件描述符来指向fd对应的文件。这两个系统调用经常用在标准输入、标准输出、标准 出错重定向。
dup()返回的新文件描述符一定是当前可用文件描述符中的最小数值;
dup2可以用fd2参数来指定新的文件描述符。如果fd2已经打开,则先关闭。如fd等于fd2, 则dup2返回fd2, 而不关闭它。
代码示例
dup2(fd, STDIN_FILENO); //标准输入重定向到 std.txt 文件中去
dup2(fd, STDOUT_FILENO); //标准输出重定向到 std.txt 文件中去
dup2(fd, STDERR_FILENO); //标准出错重定向到 std.txt 文件中去
access()
函数原型
int access(const char *path, int mode);
access()可以用来测试文件是否存在或测试其权限位,其中第一个参数path是相应的文件路径名,第二个参数是要测试的模式。其中mode说明如下:
mode | 说明 |
R_OK | 测试读许可权 |
W_OK | 测试写许可权 |
X_OK | 测试执行许可权 |
F_OK | 测试文件是否存在 |
代码示例
#include <stdio.h>
#include <unistd.h>
#define TEST_FILE "access.c"
int main(void)
{
if( access(TEST_FILE, F_OK)!=0 )
{
printf("File %s not exist!\n", TEST_FILE);
return 0;
}
printf("File %s exist!\n", TEST_FILE);
if(access(TEST_FILE, R_OK)==0)
printf("READ OK\n");
if(access(TEST_FILE, W_OK)==0)
printf("WRITE OK\n");
if(access(TEST_FILE, X_OK)==0)
printf("EXEC OK\n");
return 0;
}