文件操作
C语言中的文件读&写
#include <stdio.h>
int main()
{
FILE* fp = fopen("log.txt","r");
if(fp == NULL)
{
perror("fopen");
return 1;
}
int ct = 5;
char buf[64];
while(ct){
fgets(buf,sizeof(buf),fp);
printf(buf);
ct--;
}
/*
int ct = 5;
while(ct)
{
fputs("hello world \n",fp);
ct--;
}
*/
fclose(fp);
return 0;
}
stdin
标准输入
FILE* fp = fopen("log.txt","r");
if(fp == NULL)
{
perror("fopen");
return 1;
}
int ct = 5;
char buf[64];
while(ct){
fgets(buf,sizeof(buf),stdin);
printf(buf);
ct--;
}
stdout
标准输出
int ct = 5;
while(ct)
{
fputs("hello world \n",stdout);
ct--;
}
stderr
标准错误
int ct = 5;
while(ct)
{
fputs("hello world \n",stderr);
ct--;
}
a–追加写入
#include <stdio.h>
int main()
{
FILE* fp = fopen("log.txt","a");//append
if(fp == NULL)
{
perror("fopen");
return 1;
}
int ct = 5;
while(ct)
{
fputs("hello L \n",fp);
ct--;
}
fclose(fp);
return 0;
}
write-- 覆盖写入
#include <stdio.h>
int main()
{
FILE* fp = fopen("log.txt","w");
if(fp == NULL)
{
perror("fopen");
return 1;
}
int ct = 5;
while(ct)
{
fputs("welcome!\n",fp);
ct--;
}
fclose(fp);
return 0;
}
系统中的I/O
接口
- O_RDONLY 只读打开
- O_WRONLY只写打开
- O_RDWR读写打开
- O_CREAT若文件不存在,则创建
- O_APPEND追加写
- 打开成功返回值 大于0
- 打开失败返回1
文件描述符
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd = open("log.txt",O_WRONLY,0666);
printf("fd: %d\n",fd);
return 0;
}
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd = open("log.txt",O_WRONLY|O_CREAT,0666);
printf("fd: %d\n",fd);
return 0;
}
找标志位
open
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int f1 = open("log.txt",O_WRONLY|O_CREAT,0666);
printf("fd: %d\n",f1);
int f2 = open("log.txt",O_WRONLY|O_CREAT,0666);
printf("fd: %d\n",f2);
int f3 = open("log.txt",O_WRONLY|O_CREAT,0666);
printf("fd: %d\n",f3);
int f4 = open("log.txt",O_WRONLY|O_CREAT,0666);
printf("fd: %d\n",f4);
int f5 = open("log.txt",O_WRONLY|O_CREAT,0666);
printf("fd: %d\n",f5);
return 0;
}
write&close
const char* msg = "welcome L\n";
write(1,msg,strlen(msg));
char buff[32];
read(0,buff,32);
printf("%s\n",buff);
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main()
{
int f1 = open("log.txt",O_WRONLY|O_CREAT,0666);
if(f1 < 0){
printf("open error!\n");
}
printf("fd: %d\n",f1);
int ct = 5;
const char* msg = "hello world!\n";
while(ct)
{
write(f1,msg,strlen(msg));//strlen不需要+1
ct--;
}
close(f1);
return 0;
}
read
#include <string.h>
int main()
{
int f1 = open("log.txt",O_RDONLY);
if(f1 < 0){
printf("open error!\n");
}
printf("fd: %d\n",f1);
char c;
while(1)
{
ssize_t s = read(f1,&c,1);
if(s <= 0)
{
break;
}
write(1,&c,1);//fwrite(,,,stdout);
}
close(f1);
return 0;
}
文件标识符分配规则
从最小但是没有被使用的开始分配
关闭显示器(1)
close(1);
int f2 = open("log.txt",O_WRONLY|O_CREAT,0666);
printf("fd: %d\n",f2);
int f3 = open("log.txt",O_WRONLY|O_CREAT,0666);
printf("fd: %d\n",f3);
int f4 = open("log.txt",O_WRONLY|O_CREAT,0666);
printf("fd: %d\n",f4);
int f5 = open("log.txt",O_WRONLY|O_CREAT,0666);
printf("fd: %d\n",f5);
return 0;
关0
close(0);
int f2 = open("log.txt",O_WRONLY|O_CREAT,0666);
printf("fd: %d\n",f2);
int f3 = open("log.txt",O_WRONLY|O_CREAT,0666);
printf("fd: %d\n",f3);
int f4 = open("log.txt",O_WRONLY|O_CREAT,0666);
printf("fd: %d\n",f4);
int f5 = open("log.txt",O_WRONLY|O_CREAT,0666);
printf("fd: %d\n",f5);
return 0;
close(0);
close(2);
int f2 = open("log.txt",O_WRONLY|O_CREAT,0666);
printf("fd: %d\n",f2);
int f3 = open("log.txt",O_WRONLY|O_CREAT,0666);
printf("fd: %d\n",f3);
int f4 = open("log.txt",O_WRONLY|O_CREAT,0666);
printf("fd: %d\n",f4);
int f5 = open("log.txt",O_WRONLY|O_CREAT,0666);
printf("fd: %d\n",f5);
return 0;
int fd = open("log.txt",O_WRONLY|O_CREAT,0666);
if(fd < 0){
return 1;
}
write(fd,"hello\n",6);
write(fd,"hello\n",6);
write(fd,"hello\n",6);
write(fd,"hello\n",6);
write(fd,"hello\n",6);
close(fd);
close(1);
int fd = open("log.txt",O_WRONLY|O_CREAT,0666);
if(fd < 0){
return 1;
}
write(fd,"hello\n",6);
write(fd,"hello\n",6);
write(fd,"hello\n",6);
write(fd,"hello\n",6);
write(fd,"hello\n",6);
close(fd);
重定向
输出重定向
close(1);
int fd = open("log.txt",O_WRONLY|O_CREAT,0666);
if(fd < 0){
return 1;
}
write(1,"hello\n",6);
write(1,"hello\n",6);
write(1,"hello\n",6);
write(1,"hello\n",6);
write(1,"hello\n",6);
close(fd);
close(1);
int fd = open("log.txt",O_WRONLY|O_CREAT,0666);
if(fd < 0){
return 1;
}
printf("hello you:%d\n",123);
printf("hello you:%c\n",'v');
printf("hello you:%f\n",3.335);
fflush(stdout);
close(1);
int fd = open("log.txt",O_WRONLY|O_CREAT,0666);
if(fd < 0){
return 1;
}
printf("hello",stdout);
printf("hello",stdout);
printf("hello",stdout);
int fd = open("log.txt",O_WRONLY|O_CREAT,0666);
if(fd < 0){
return 1;
}
printf("hello",stdout);
printf("hello",stdout);
printf("hello",stdout);
重定向本质是修改文件描述符下标对应的struct file 指向的内容*
struct FILE 是一个结构体,里面必定包含一个成员叫fd
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
umask(0);
int fd = open("log.txt",O_WRONLY|O_CREAT,0666);
if(fd < 0)
{
perror("open");
return 1;
}
//都属于C,FILE*
printf("hello printf!\n");//stdout printf内部封装了stdout
fprintf(stdout,"hello fprintf!\n");
fputs("hello fputs %d %c %c\n",stdout);
close(fd);
return 0;
}
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
close(1);//fd = 1
umask(0);
int fd = open("log.txt",O_WRONLY|O_CREAT,0666);
if(fd < 0)
{
perror("open");
return 1;
}
//都属于C,FILE*,只认stdout(FILE*)的接口
printf("hello printf!\n");//stdout printf内部封装了stdout
fprintf(stdout,"hello fprintf!\n");
fputs("hello fputs %d %c %c\n",stdout);
close(fd);
return 0;
}
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
close(1);//fd = 1
umask(0);
int fd = open("log.txt",O_WRONLY|O_CREAT,0666);
if(fd < 0)
{
perror("open");
return 1;
}
//都属于C,FILE*,只认stdout(FILE*)的接口
printf("hello printf!\n");//stdout printf内部封装了stdout
fprintf(stdout,"hello fprintf!\n");
fflush(stdout);//让文件里把信息显示出来
fputs("hello fputs %d %c %c\n",stdout);
close(fd);
return 0;
}
标准输入
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
umask(0);
int fd = open("log.txt",O_RDONLY,0666);
if(fd < 0)
{
perror("open");
return 1;
}
//都属于C,FILE*,只认stdout(FILE*)的接口
printf("hello printf!\n");//stdout printf内部封装了stdout
fprintf(stdout,"hello fprintf!\n");
fputs("hello fputs %d %c %c\n",stdout);
fflush(stdout);//让文件里把信息显示出来
char buff[50];
fgets(buff,50,stdin);
printf("%s\n",buff);
close(fd);
return 0;
}
输出重定向
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
close(0);//stdin
umask(0);
int fd = open("log.txt",O_RDONLY,0666);
if(fd < 0)
{
perror("open");
return 1;
}
//都属于C,FILE*,只认stdout(FILE*)的接口
printf("hello printf!\n");//stdout printf内部封装了stdout
fprintf(stdout,"hello fprintf!\n");
fputs("hello fputs %d %c %c\n",stdout);
fflush(stdout);//让文件里把信息显示出来
char buff[50];
fgets(buff,50,stdin);
printf("%s\n",buff);
close(fd);
return 0;
}
追加重定向
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
close(1);//fd = 1
umask(0);
int fd = open("log.txt",O_WRONLY|O_APPEND);//a
if(fd < 0)
{
perror("open");
return 1;
}
//都属于C,FILE*,只认stdout(FILE*)的接口
printf("hello printf!\n");//stdout printf内部封装了stdout
fprintf(stdout,"hello fprintf!\n");
fputs("hello fputs %d %c %c\n",stdout);
fflush(stdout);//让文件里把信息显示出来
return 0;
}
凡是显示到显示器上面的内容/从键盘读取的内容,都是字符,所以,键盘和显示器一般称之为“字符设备”
scanf/printf格式化输入输出需要把数字依据ASCII表转化为字符
查看fd 1&2的区别
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main()
{
printf("hello printf!\n");//stdout
perror("perror");//stderr
fprintf(stdout,"stdout : hello fprintf\n");
fprintf(stderr,"stderr : hello fprintf\n");
return 0;
}
重定向1所以不往显示器上打印,但是不影响2所以fd=2的内容在显示器上显示
批量替换
NOMAL模式
- 1、按ESC
- :%s/替换/被替换/g
使用dup2系统调用
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main()
{
umask(0);
int fd = open("log.txt",O_WRONLY|O_CREAT,0666);
if(fd < 0){
perror("open");
return 1;
}
close(1);//打开之后再重定向
dup2(fd,1);
printf("hello printf\n");
fprintf(stdout,"hello fprintf\n");
fputs("hello fputs:%d %c %f\n",stdout);
fflush(stdout);
close(fd);
return 0;
}
在myshell添加重定向动能
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <ctype.h>
#include <sys/stat.h>
#include <fcntl.h>
#define len 1024
#define num 32
int main()
{
int type = 0;//0 > 1 >> 2 <
char cmd[len];
char* myarg[num];
while(1)
{
printf("[L@my_centos_mc dir]$");
fgets(cmd,len,stdin);
cmd[strlen(cmd)-1] = '\0';
//printf("%s",cmd);
//解析字符串
//char* start = cmd + strlen(cmd) - 1;
char* start = cmd;
while(*start != '\0')
{
if(*start == '>')
{
type = 0;
*start = '\0';
start ++;
if(*start == '>')
{
type = 1;
start++;
}
break;
}
if(*start == '<')
{
type = 2;
*start = '\0';
start++;
break;
}
//start --;
start++;
}
if(*start != '\0')
{
while(isspace(*start)){
start++;
}
//printf("%s\n",start);
}
else{
start = NULL;
}
myarg[0] = strtok(cmd," ");
int i = 1;
while(myarg[i] = strtok(NULL," "))
{
i++;
}
pid_t id = fork();
if(id == 0)
{
//child
if(start != NULL)
{
if(type == 0){
int fd = open(start,O_CREAT|O_WRONLY,0644);
if(fd < 0)
{
perror("open");
exit(2);
}
dup2(fd,1);
}
}
else if(type == 1)
{
int fd = open(start,O_APPEND,0644);
if(fd < 0){
perror("open");
exit(2);
}
dup2(fd,1);
}
else if(type == 2)
{
int fd = open(start,O_RDONLY,0644);
dup2(fd,0);
}
else{
}
execvp(myarg[0],myarg);
exit(10);
}
int status = 0;
pid_t ret = waitpid(id,&status,0);
if(ret > 0)
{
printf("exit code: %d\n",WEXITSTATUS(status));
}
}
/*
char name[32];
while(1)
{
gethostname(name,sizeof(name)-1);
printf("%s\n",name);
}*/
return 0;
}
FILE
- IO相关函数接口与系统调用函数相对应,并且库函数封装系统调用,所以本质上,访问文件都是通过fd访问的
- C库当中的FILE结构体内部,封装了fd
解释Linux下一切皆文件
缓冲
#include <stdio.h>
#include <unistd.h>
int main()
{
/*
printf("hello world!\n");//先执行hello world\n
sleep(3);
*/
printf("hello world!");//先被保存到缓冲区3秒再被刷新出来
sleep(3);
//fflush(stdout);//会被立即刷新出来
return 0;
}
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main()
{
//C语言函数
printf("hello printf\n");
fprintf(stdout,"hello fprintf\n");
//system
const char* msg = "hello write\n";
write(1,msg,strlen(msg));
return 0;
}
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main()
{
//C语言函数
printf("hello printf\n");
fprintf(stdout,"hello fprintf\n");
//system
const char* msg = "hello write\n";
write(1,msg,strlen(msg));
fork();
return 0;
}
文件系统
- 模式
- 磁盘链接数
- 文件所有者
- 组
- 大小
- 最后修改日期
- 文件名
磁盘
查看磁盘
inode
查看inode编号:ls -l -i
软硬链接
#include <stdio.h>
int main()
{
printf("hello new !\n");
return 0;
}
建立软链接
ln -s file file-s
建立硬链接
ln file file-h
- Access:最近被访问的时间
- Modify:最近被修改的时间
- Change:文件属性的变化
动态库和静态库
Linux
.so:动态库
.a:静态库
Windows
.dll:动态库
.lib:静态库
把动态库变为静态库
gcc -o file file.c -static
- 静态库(.a):程序在编译链接时把库的代码链接到可执行文件中。程序运行时将不再需要静态库
- 动态库(.so):程序在运行时才去链接动态库的代码,多个程序共享使用库的代码
- 一个动态库链接的可执行文件仅仅 包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码
- 在可执行文件开始运行前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称之为动态链接
- 动态库可以在多个程序中共享,所以动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间
静态库
缺点:占空间(内存+磁盘),多个静态库程序加载时,一定会有在内存中存在大量重复代码
优点:与库无关,不需要库
动态库:
优点:节省空间(内存空间),库文件是通过地址空间共享的
缺点:必须依赖库,没有库,无法运行
生成静态库
- 生成静态库:
ar -rc libmymath.a file.o test.o
ar是gnu归档工具,rc(replace and create)
cat Makefile
mylib=libcal.a
CC=gcc
$(mylib):add.o sub.o
ar -rc $(mylib) $^
%.o:%.c
$(CC) -c $<
.PHONY:clean
clean:
rm -f $(mylib) *.o
.PHONY:output
output:
mkdir -p mathlib/lib
mkdir -p mathlib/include
cp *.h mathlib/include
cp *.a mathlib/lib
- 查看静态库中的目录列表:
ar -tv libmymath.a test.o file.o
t:列出静态库的文件 v:verbose 详细信息
cat test.c
#include <stdio.h>
#include <add.h>
int main()
{
int x = 10;
int y = 20;
int z = my_add(x,y);
printf("%d\n",z);
return 0;
}
- -I :头文件在哪里
- -L:库文件在哪里
- -l:链接哪个库
安装库的过程
把库拷贝到系统路径下
sudo cp mathlib/include/* /usr/include/
生成动态库
- shared:表示生成共享库格式
- FPIC:产生位置无关码
- 库名规则:libxxx.so
使用动态库
- l:链接动态库,只要库名即可(去掉lib及版本号)
- L:链接库所在的路径
运行动态库
- 拷贝.so文件到系统共享库路径下,一般指/usr/lib
- 更改LD_LIBRARY_PATH
- ldconfig 配置 /etc/ld.so.conf.d/,ldconfig更新
使用外部库
- -lm 表示要链接libm.so或libm.a库文件