Linux基础IO(一)之回顾C语言文件接口
文章目录
- 共识原理
- 回顾C文件接口
- 打开文件的方式
- 以w的方式打开文件
- 以a的方式打开文件
- stdin & stdout & stderr
共识原理
1.文件=内容+属性
就算内容是空的,也会有属性,内容和属性(两者都是数据)都要在磁盘当中保存
2.文件分为 打开的文件 和 没打开的文件
3.打开的文件:
要对文件进行操作的时候,先要把文件 fopen
,
那么是谁打开的文件?进程!!— 本质是研究进程和文件的关系!
把一个文件打开就是为了访问这个文件,
访问文件都是通过代码去访问的(读、写、改和对属性做获取操作等)
我们通过执行指令、代码的方式对打开的文件进行访问势必是CPU来执行的。
所以,根据冯诺依曼体系结构,一个文件被打开,该文件一定先被加载到内存。
是属性还是内容被加载进内存?一个文件的属性必须先被加载到内存!
是否加载内容(取决于文件是否需要被读取、修改)
进程 : 打开的文件 = 1 : n
(比如:Linux操作系统会默认打开stdin,stdout,stderr
)
操作系统内部一定存在大量的被打开的文件!
– OS需要管理这些被打开的文件!
– 如何管理?
– 先描述再组织
– 在内核中,一个被打开的文件都必须有自己的文件打开对象,包含文件很多的属性。
struct XXX
{
文件属性;
struct XXX*next;
};
用next指针就可以把文件对象链接起来
所以,我们就可以把文件以链表的形式管理起来!
对打开文件的管理就转换成了对链表的增删查改。
4.没打开的文件:
在哪里放着?
没打开的文件没有人去访问它,
所以它在存储介质上放着 – 最常见的存储介质 -> 磁盘!!!
最关注什么问题?
没有被打开的文件非常多!
文件如何被分门别类地放置好
– 本质:我们需要进行快速的 增删查改
在增删查改文件之前必须得找到文件。(文件路径、文件名等)
所以就是如何存储的问题。
回顾C文件接口
makefile
myfile:myfile.c
gcc -o $@ $^ -std=c99
.PHONY:clean
clean:
rm -rf myfile
fopen
要包含的头文件也是stdio.h
所以文件操作默认就在c语言的第一个库函数中
std就是标准的意思,io就是输入输出
一个文件没有被打开时,就在磁盘上。
所以访问文件就是访问磁盘的过程,也就是io的过程
输出到显示器、从键盘输入读取、读取文件等都叫io。
返回值是FILE*
,文件指针(文件句柄)。
打开了一个文件用完之后就可以关闭文件了。
以写的方式打开文件,系统就会新建这个文件(权限默认普通文件的权限)
myfile.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
FILE*fp=fopen("log.txt","w");
if(fp==NULL)
{
perror("fopen");
return 1;
}
fclose(fp);
return 0;
}
打开文件的路径和文件名,如果前面没有带路径就是默认的log.txt
,
或者在Linux中 ./log.txt
,表示默认在当前路径下新建一个文件
带了路径就去指定路径下创建,当前路径指进程的当前路径。
如果更改了当前进程的cwd
,就可以把文件新建到其他目录。
验证:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
printf("Pid:%d\n",getpid());
FILE*fp=fopen("log.txt","w");
if(fp==NULL)
{
perror("fopen");
return 1;
}
fclose(fp);
sleep(1000);
return 0;
}
cwd
当前进程的工作路径
所以新建的文件就会新建在 pwd
的路径下。
如何修改当前进程的工作目录?
chdir
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
chdir("/home/lll");
printf("Pid:%d\n",getpid());
FILE*fp=fopen("log.txt","w");
if(fp==NULL)
{
perror("fopen");
return 1;
}
fclose(fp);
sleep(1000);
return 0;
}
打开文件的方式
以w的方式打开文件
向文件流当中写入指定大小的、和指定地址的字节流数据、信息流数据、字符串等
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main()
{
printf("Pid:%d\n",getpid());
FILE*fp=fopen("log.txt","w");
if(fp==NULL)
{
perror("fopen");
return 1;
}
const char*msg="Hello linux";
fwrite(msg,strlen(msg),1,fp);
fclose(fp);
return 0;
}
把msg里面的字符串改成了 abcd
如果文件不存在就创建文件,如果文件存在,就先把文件内容清空。
w:写入之前,都会对文件进行清空处理!
把 Hello Linux
重定向到 log.txt
中(输出重定向)
本质就是以写的方式打开并写入(w)。
先清空再写入
>log.txt
也可以清空文件,因为重定向符号一定先把文件以 ‘w’ 的方式打开,
所以里面的内容一定先会被清空,再被写入。
验证:把文件以写的方式打开后直接关闭
strlen(msg)
要不要加1呢
验证:先把 strlen
+1,运行后,出现了乱码。
很明显这个乱码就是 \0
,\0
是可以被写入的,
因为它也是字符,不过是不可显字符,
被 vim
这种文本编辑器就会被解释为乱码。
所以,要不要+1呢?
不要!字符串以 \0
结尾,是c语言的规定,和文件没有关系。
以a的方式打开文件
如果文件不存在就先创建这个文件,然后在文件的结尾去写。(追加写!)
所以 >>
是以 a
方式打开(追加写),>
是以 w
方式打开(清空并从头写)。
Linux下一切皆文件!!!!—— TODO
stdin & stdout & stderr
C默认会打开三个输入输出流,分别是stdin, stdout, stderr
C++默认也会打开三个输入输出流,分别是 cin, cout, cerr
结论:如果我们像向显示器打印,我们就可以向这些文件流写入。
仔细观察发现,这三个流的类型都是FILE*
, fopen
返回值类型,文件指针
fwrite例:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main()
{
printf("Pid:%d\n",getpid());
FILE*fp=fopen("log.txt","a");
if(fp==NULL)
{
perror("fopen");
return 1;
}
const char*msg="abcd\n";
fwrite(msg,strlen(msg),1,stdout);
fclose(fp);
return 0;
}
fprintf例:
fwrite(msg,strlen(msg),1,stdout); --> fprintf(stdout,"%s:%d\n",msg,1234);