1.linux系统如何管理文件
硬盘中的静态文件和inode:
(1)硬盘分为两大区域:一个是硬盘内容管理表项,另一个是真正存储内容的区域。先去读取硬盘内容管理表,找到要访问的存储内容的区域,再用得到我们要的文件。
(2)每一个文件有一个信息列表(叫inode,i节点,其实质是一个结构体,有很多元素,每个元素记录了这个文件的信息,有包括文件名、扇区号、块号等信息)
内存中被打开的文件和vnode:
(1)在程序中打开的文件属于某个进程,进程有对应的进程信息表,表中的指针会指向文件管理表,文件管理表中记录了当前进程的相关信息。
(2)文件的管理结构体vnode记录了一个被打开的文件的各种信息。
1.多次打开同一文件
(1)设置fd1,fd2读取文件,经过实验验证,证明了结果是fd1和fd2分别读。
(2)设置fd1,fd2写入文件,经过实验验证,证明了结果是fd1和fd2分别写
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{
int fd1 = -1, fd2 = -1; // fd 就是file descriptor,文件描述符
char buf[100] = {0}; //用来存放读取文件内容的buf
char writebuf[20] = "l love linux";
int ret = -1;
// 第一步:打开同一个文件,返回两个文件描述符
fd1 = open("a.txt", O_RDWR | O_TRUNC | O_CREAT , 0666);
fd2 = open("a.txt", O_RDWR | O_TRUNC | O_CREAT , 0666);
if ((-1 == fd1) || (fd2 == -1))
{
perror("文件打开错误");
_exit(-1);
}
else
{
printf("文件打开成功,fd1 = %d. fd2 = %d.\n", fd1, fd2);
}
#if 0 //先关掉写文件
while (1)
{
// 写文件
ret = write(fd1, "ab", 2);
if (ret < 0)
{
perror("write失败");
_exit(-1);
}
else
{
printf("write成功,写入了%d个字符\n", ret);
}
ret = write(fd2, "cd", 2);
if (ret < 0)
{
perror("write失败");
_exit(-1);
}
else
{
printf("write成功,写入了%d个字符\n", ret);
}
sleep(1);
}
#endif
#if 1 //先打开读文件
while(1)
{
// 读文件fd1
memset(buf, 0, sizeof(buf)); //先清空用来存放读取内容的buf
ret = read(fd1, buf, 2);
if (ret < 0)
{
printf("read失败\n");
_exit(-1);
}
else
{
printf("fd1:[%s].\n", buf);
}
sleep(1);
// 读文件fd2
memset(buf, 0, sizeof(buf));
ret = read(fd2, buf, 2);
if (ret < 0)
{
printf("read失败\n");
_exit(-1);
}
else
{
printf("fd2:[%s].\n", buf);
}
}
#endif
// 第三步:关闭文件
close(fd1);
close(fd2);
_exit(0);
}
(3)有时候我们希望接续写而不是分别写?办法就是在open时加O_APPEND标志即可,对文件的读写是原子操作。
2.文件共享的实现方式
(1)文件共享就是同一个文件被多个独立的读写体去同时操作。
(2)常见的有3种文件共享的情况:第一种是同一个进程中多次使用open打开同一个文件,第二种是在不同进程中去分别使用open打开同一个文件(这时候因为两个fd在不同的进程中,所以两个fd的数字可以相同也可以不同),第三种情况是后面要学的,linux系统提供了dup和dup2两个API来让进程复制文件描述符。
(3)dup和dup2函数
使用dup进行文件描述符复制:会返回一个新的文件描述符
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define FILENAME "1.txt"
int main(void)
{
int fd1 = -1, fd2 = -1;
fd1 = open(FILENAME, O_RDWR | O_CREAT | O_TRUNC, 0644);
if (fd1 < 0)
{
perror("open");
return -1;
}
printf("fd1 = %d.\n", fd1);
close(1); // 1就是标准输出stdout
// 复制文件描述符
fd2 = dup(fd1); // fd2一定等于1,因为前面刚刚关闭了1,这句话就把
if (fd2 < 0) // 1.txt文件和标准输出就绑定起来了,所以以后输出
{ // 到标准输出的信息就可以到1.txt中查看了。
perror("dup");
return -1;
}
printf("fd2 = %d.\n", fd2);
printf("this is for test\n");
close(fd1);
return -1;
}
dup2复制的文件描述符:dup2允许用户指定新的文件描述符的数字
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define FILENAME "1.txt"
int main(void)
{
int fd1 = -1, fd2 = -1;
fd1 = open(FILENAME, O_RDWR | O_CREAT | O_TRUNC, 0644);
if (fd1 < 0)
{
perror("open");
return -1;
}
printf("fd1 = %d.\n", fd1);
fd2 = dup2(fd1, 16);
printf("fd2 = %d.\n", fd2);
while (1)
{
write(fd1, "aa", 2);
sleep(1);
write(fd2, "bb", 2);
}
close(fd1);
return -1;
}
3.fcntl函数
(1)fcntl的常用cmd,F_DUPFD这个cmd的作用是复制文件描述符(作用类似于dup和dup2)
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define FILENAME "1.txt"
int main(void)
{
int fd1 = -1, fd2 = -1;
fd1 = open(FILENAME, O_RDWR | O_CREAT | O_TRUNC, 0644);
if (fd1 < 0)
{
perror("open");
return -1;
}
printf("fd1 = %d.\n", fd1);
fd2 = fcntl(fd1, F_DUPFD, 6);
printf("fd2 = %d.\n", fd2);
while (1)
{
write(fd1, "aa", 2);
sleep(1);
write(fd2, "bb", 2);
}
close(fd1);
return -1;
}
4.标准IO库
(1)标准IO是C库函数,而文件IO是linux系统的API
(2)常见的标准IO库函数有:fopen、fclose、fwrite、fread、ffulsh、fseek
读文件代码:
#include <stdio.h> // standard input output
#include <stdlib.h>
#include <string.h>
#define FILENAME "1.txt"
int main(void)
{
FILE *fp = NULL;
size_t len = -1;
char buf[100] = {0}; //用来储存读取文件的内容
fp = fopen(FILENAME, "r+");
if (NULL == fp)
{
perror("fopen");
exit(-1);
}
printf("fopen success. fp = %p.\n", fp);
// 在这里去读文件
memset(buf, 0, sizeof(buf));
len = fread(buf, 1, 10, fp);
printf("len = %d.\n", len);
printf("buf is: [%s].\n", buf);
fclose(fp);
return 0;
}
写文件代码:
#include <stdio.h> // standard input output
#include <stdlib.h>
#include <string.h>
#define FILENAME "1.txt"
int main(void)
{
FILE *fp = NULL;
size_t len = -1;
int array[10] = {1, 2, 3, 4, 5};
fp = fopen(FILENAME, "w+");
if (NULL == fp)
{
perror("fopen");
exit(-1);
}
printf("fopen success. fp = %p.\n", fp);
// 在这里去写文件
len = fwrite(array, 4, 10, fp);
printf("len = %d.\n", len);
fclose(fp);
return 0;
}