目录
一、基础IO
1. C语言文件读写
2. 标志位传参
3. C语言与系统调用关系
二、文件系统
1. 文件描述符
2. 输入输出重定向
一、基础IO
文件调用
- 库函数接口: fopen、fclose、fwrite、fread、fseek
- 系统调用接口:open、close、write、read、lseek
1. C语言文件读写
- r/w/a :读/写/追加
- 若打开的文件不存在,“r”报错,“w/a”创建
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
int main()
{
//FILE* pf = fopen("test.txt", "w");
//FILE* pf = fopen("test.txt", "a");
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
exit(errno);
}
//w
// int cnt = 5;
// while (cnt--)
// fprintf(pf, "%s\n", "hello world -- write");
//a
// int cnt = 5;
// while (cnt--)
// fprintf(pf, "%s\n", "append");
//r
char buffer[64];
while (fgets(buffer, sizeof(buffer) - 1, pf))
{
buffer[strlen(buffer) - 1] = 0;
printf("%s\n", buffer);
}
return 0;
}
2. 标志位传参
#include <stdio.h>
#define ONE (1 << 1)
#define TWO (1 << 2)
#define THREE (1 << 3)
#define FOUR (1 << 4)
void Show(int flag)
{
if (flag & ONE)
printf("one\n");
if (flag & TWO)
printf("two\n");
if (flag & THREE)
printf("three\n");
if (flag & FOUR)
printf("four\n");
}
void ShowTest()
{
Show(ONE);
printf("-----------\n");
Show(TWO);
printf("-----------\n");
Show(TWO | THREE);
printf("-----------\n");
Show(TWO | THREE | FOUR);
}
int main()
{
ShowTest();
return 0;
}
3. C语言与系统调用关系
- "w" ----> O_WRONLY | O_CREAT | O_TRUNC
- "a" ----> O_WRONLY | O_CREAT | O_APPEND
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
int main()
{
umask(0); //只修改当前进程的umask
//int fd = open("test.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);
//int fd = open("test.txt", O_WRONLY | O_CREAT | O_APPEND, 0666);
int fd = open("test.txt", O_RDONLY);
if (fd < 0)
{
perror("open");
return 1;
}
//写/追加
// int cnt = 5;
// char outBuffer[64] = {0};
// while (cnt--)
// {
// sprintf(outBuffer, "%s: %d\n", "hello --- a", cnt);
// write(fd, outBuffer, strlen(outBuffer));
// }
//读
char buffer[1024];
ssize_t num = read(fd, buffer, sizeof(buffer) - 1);
if (num > 0)
{
buffer[num] = 0;
}
printf("%s", buffer);
return 0;
}
二、文件系统
在Linux中,一切皆文件,不仅普通的文件和目录,块设备、管道、socket等等,都是由文件系统管理的。在Linux中的文件系统会给每个文件分配两个数据结构:索引节点(index node)和目录项(directory entry),它们都主要是被用来记录文件的元信息和目录层次结构。
- 索引节点,inode,用来记录文件的元信息,比如inode编号、文件大小、访问权限、创建时间、修改时间、数据在磁盘的位置等。索引节点是文件的唯一标识,它们之间一一对应,也同样都是被存储在硬盘当中,索引节点也是会占用磁盘的存储空间的。
- 目录项,dentry,用来记录文件的名字,索引节点指针以及与其他目录项的层级关联关系。多个目录项关联起来,就会形成目录结构,但是它与索引节点不相同的是,目录项是由内核维护的一个数据结构,不是存放咋磁盘中,而是缓存在内存里面。目录项包括文件名和inode节点号。
1. 文件描述符
文件描述符(file descripter)FD:Linux内容默认情况下一个进程只能打开1024个文件,内核为了管理进程,当一个进程打开了哪些文件,内核就会维护一个表,这个表就会记录这个进程打开了哪些文件,然后给每个文件进行编号,这个编号就叫文件描述符(句柄),默认文件描述符的范围为0-1023。
三个标准输入输出流:
- stdin:标准输入,0
- stdout:标准输出,1
- stderr:标准错误,2
FILE ----> 结构体
文件描述符表:struct file* fd_array[]
文件分配规则:寻找最小且没被占用的下标
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#define TEST_FILE(number) "test"#number
int main()
{
umask(0);
printf("stdin ---> fd : %d\n", stdin->_fileno); //0
printf("stdout ---> fd : %d\n", stdout->_fileno); //1
printf("stderr ---> fd : %d\n", stderr->_fileno); //2
//close(0);
//close(2);
close(1); //关闭文件描述符对应下标的文件
//关闭文件描述符表的 1 后, fd0 会被分配到 1 的位置,也就是原本stdout的位置
//而原本输出到stdout的数据,会写入 fd0 中
int fd0 = open(TEST_FILE(0), O_WRONLY | O_CREAT | O_APPEND, 0666);
int fd1 = open(TEST_FILE(1), O_WRONLY | O_CREAT | O_APPEND, 0666);
int fd2 = open(TEST_FILE(2), O_WRONLY | O_CREAT | O_APPEND, 0666);
int fd3 = open(TEST_FILE(3), O_WRONLY | O_CREAT | O_APPEND, 0666);
printf("fd : %d\n", fd0);
printf("fd : %d\n", fd1);
printf("fd : %d\n", fd2);
printf("fd : %d\n", fd3); //fd分配规则,寻找最小的且没被占用的下标
fprintf(stdout, "fd : %d\n", fd3); //打印到 f0 对应的文件
fflush(stdout);
close(fd0);
close(fd1);
close(fd2);
close(fd3);
return 0;
}
2. 输入输出重定向
int dup2(int old_fd, int new_fd)
重定向:将新的文件文件描述符充当老的文件描述符的一份拷贝(old_fd内容 拷贝到 new_fd内容)
上层的fd不变,在内核中更改fd对应的struct file*地址
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
int main()
{
umask(0);
//int fd = open("test.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);
//int fd = open("test.txt", O_WRONLY | O_CREAT | O_APPEND, 0666);
int fd = open("test.txt", O_RDONLY);
if (fd < 0)
{
perror("open");
return 1;
}
//输出重定向
// dup2(fd, 1);
// printf("open fd: %d\n", fd);
// fprintf(stdout, "open fd: %d\n", fd);
// const char* msg = "hello world\n";
// write(1, msg, strlen(msg));
// fflush(stdout);
//输入重定向
dup2(fd, 0);
char line[1024];
while (1)
{
printf("> ");
if (fgets(line, sizeof(line) - 1, stdin) == NULL)
break;
printf("%s", line);
}
close(fd);
return 0;
}