Linux 基础IO(个人笔记)


1.C文件IO操作

1.1 hello.c写文件

#include<stdio.h>
#include<string.h>

int main()
{
	FILE* fp = fopen("myfile", "w");
	if (fp == NULL)
	{
		printf("fopen error\n");
	}

	const char* msg = "hello LJH\n";
	int count = 5;
	while (count--)
	{
		fwrite(msg, strlen(msg), 1, fp);
	}
	fclose(fp);

	return 0;
}

1.2 hello.c读文件

#include<stdio.h>
#include<string.h>

int main()
{
	FILE* fp = fopen("myfile", "r");
	if (!fp)
	{
		printf("fopen error!\n");
	}

	char buf[1024];
	const char* msg = "hello LJH!\n";
	while (1)
	{
		size_t s = fread(buf, 1, strlen(msg), fp);
		if (s > 0)
		{
			buf[s] = 0;
			printf("%s", buf);
		}
		if (feof(fp))
		{
			break;
		}
	}
	fclose(fp);

	return 0;
}

1.3 stdin&stdout&stderr

C默认会打开三个输入输出流:stdin,stdout,stderr
且三个流的类型都是FILE*

2.系统文件I/O

系统接口来访问文件

2.1 hello.c写文件

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main()
{
  umask(0);
  int fd = open("myfile", O_WRONLY | O_CREAT, 0644);
  if (fd < 0)
  {
    perror("open");
    return 1;
  }

  int count = 5;
  const char *msg = "hello LJH!\n";
  int len = strlen(msg);
  while (count--)
  {
    write(fd, msg, len);
  }

  close(fd);
  return 0;
}

2.2 hello.c读文件

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main()
{
  int fd = open("myfile", O_RDONLY);
  if (fd < 0)
  {
    perror("open");
    return 1;
  }

  const char *msg = "hello LJH\n";
  char buf[1024];
  while (1)
  {
    ssize_t s = read(fd, buf, strlen(msg));
    if (s > 0)
    {
      printf("%s", buf);
    }
    else
    {
      break;
    }
  }
  close(fd);

  return 0;
}

2.3 open函数介绍

//所需要的头文件
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>

//函数参数介绍
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

//pathname: 要打开或创建的目标文件
//flags标记位: 打开文件时,可以传入多个参数选项,用下面的一个或者多个常量进行“或”运算,构成flags。
//flags标记位参数:
//O_RDONLY: 只读打开
//O_WRONLY: 只写打开
//O_RDWR : 读,写打开
//这三个常量,必须指定一个且只能指定一个
//O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限
//O_APPEND: 追加写
//返回值:
 //成功:新打开的文件描述符
 //失败:-1

2.4 文件描述符 fd

fd其实是文件描述符表的数组下标
Linux进程默认情况下会有3个缺省打开的文件描述符,分别是标准输入0, 标准输出1, 标准错误2.
在这里插入图片描述

2.4.1 文件描述符的分配规则

在files_struct数组当中,找到当前没有被使用的最小的一个下标,作为新的文件描述符。

2.4.2 重定向

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
int main()
{
   close(1);
   int fd = open("myfile", O_WRONLY|O_CREAT, 00644);
   if(fd < 0){
   perror("open");
   return 1;
 }
   printf("fd: %d\n", fd);
   fflush(stdout);
 
   close(fd);
   exit(0);
}

本应该通过文件描述符输出到显示器上的内容,输出到文件myfile当中,fd=1,这就是文件重定向.
在这里插入图片描述

2.4.3 dup2系统调用

#include <unistd.h>
int dup2(int oldfd, int newfd);

测试代码

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main()
{
  int fd = open("myfile", O_RDONLY);
  if (fd < 0)
  {
    perror("open");
    return 1;
  }
  dup2(fd, 0);
  close(fd);
  char buf[1024];
  while (1)
  {
    if(fgets(buf,sizeof(buf),stdin)==NULL)
    {
      break;
    }
    printf("Read:%s",buf);
    sleep(1);
  }
  return 0;
}

2.4.4 C文件结构体FILE

IO相关函数与系统调用接口对应,并且库函数封装系统调用,所以本质上,访问文件都是通过fd访问
所以C库当中的FILE结构体内部,必定封装了fd。
在这里插入图片描述
在这里插入图片描述

2.4.5 C文件缓冲区

这里解释下语言层面的缓冲区
先看代码

#include <stdio.h>
#include <string.h>
int main()
{
   const char *msg0="hello printf\n";
   const char *msg1="hello fwrite\n";
   const char *msg2="hello write\n";
   printf("%s", msg0);
   fwrite(msg1, strlen(msg0), 1, stdout);
   write(1, msg2, strlen(msg2));
   fork();
   return 0;
}

这里进行./hello>file后,打印结果如下

hello write
hello printf
hello fwrite
hello printf
hello fwrite

原因是:
1.C库函数写入文件时是全缓冲,而写入显示器是行缓冲
2.当文件重定向到普通文件时,数据的缓冲方式由行缓冲变成了全缓冲
3.然而放在缓冲区的数据就不会被立即刷新,fork之后也是如此
4.但进程退出后,会统一刷新,写入文件中
5.但是fork之后,父子数据发生写时拷贝,父进程准备刷新的时候,子进程也就有了同样的一份数据,也就是两份数据
6.write系统调用,就没有所谓的缓冲区
在这里插入图片描述

3. 文件系统

权限 硬链接数 文件所有者 文件所属组 文件大小 文件最后修改时间 文件名
在这里插入图片描述
除了ls -l 查看之外,stat+文件名,能查看更多信息
在这里插入图片描述
从硬件开始了解文件系统
在这里插入图片描述
磁盘存储的逻辑抽象结构
将磁盘盘片想象成为线性空间

在这里插入图片描述
以上是按照扇区进行存取,也可以基于文件系统,按照文件块为单位进行数据存取,也就是LBA
在这里插入图片描述
一个磁盘都会进行分区管理,一般的磁盘500g内存,进行分区管理
然而管理磁盘内存是可以进行迁移的,要管好100g,也就只需要管好2g
在这里插入图片描述
保存文件属性是通过inode保存
inode节点表:存放文件属性:文件大小,所有者,最近修改时间等
在这里插入图片描述
数据区:存放文件内容
在这里插入图片描述
inode位图:每个bit表示一个inode是否空闲可用
块位图:记录data block中那个数据块已经被占用,那个数据块没有被占用
超级块:存放文件系统本身的结构信息,如果被破坏,整个文件系统瘫痪
在这里插入图片描述

3.1文件的软硬链接

操作系统在磁盘中找文件不是通过文件名,而是通过inode,Linux中可以让多个文件名对应同一个inode,也就是不同分区可能会有相同的inode

删除文件其实是由两步组成:
1.在目录中将文件和inode的映射关系删除
2.将文件的硬链接数减1,如果减到了0,则将对应的磁盘文件释放掉。

软链接是通过名字引用另一个文件,可以理解为windows中桌面快捷方式的创建,是一个独立的文件,而硬链接不是一个独立的文件,而是在指定目录内部的一组映射关系:文件名<—>inode的映射关系

3.1.1 软链接

在Linux中,创建软链接(符号链接)可以使用 ln 命令,配合 -s 参数。软链接是指向另一个文件或目录的引用。

ln -s [目标文件或目录] [链接名称]

软链接可以跨文件系统,而硬链接不能。
如果目标文件被删除,软链接将变为“悬挂”状态,仍然存在但指向无效。
软链接的名称可以是相对路径或绝对路径。

3.1.2 硬链接

在Linux中,创建硬链接可以使用 ln 命令,不需要任何额外的参数。硬链接是指向同一物理文件的不同目录项。

ln [目标文件] [链接名称]

硬链接不能跨文件系统。
硬链接与原文件共享相同的 inode,因此它们是同一个文件的不同表示。
删除原文件并不会影响硬链接,因为它们仍然指向相同的数据。
目录通常不允许创建硬链接,除非使用特权权限。

4. 动静态库

静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库

动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。

动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。

静态库的本质是将库中的源代码直接翻译成为.o目标的二进制文件,然后打包在一起

静态库生成makefile文件参考

static-lib=libmymath.a

$(static-lib):Add.o Div.o Mul.o Sub.o
	ar -rc $@ $^
%.o:%.c
	gcc -c $<
#Test:Add.o Div.o Mul.o Sub.o TestMain.o
#	gcc -o $@ $^

.PHONY:output
output:
	mkdir -p mymath_lib/include
	mkdir -p mymath_lib/lib
	cp -f *.h mymath_lib/include
	cp -f *.a mymath_lib/lib

.PHONY:clean
clean:
	rm -rf *.o *.a mymath_lib

动态库生成Makefile文件参考

dy-lib=libmymath.so

$(dy-lib):Add.o Div.o Mul.o Sub.o
	gcc -shared -o $@ $^
%.o:%.c
	gcc -fPIC -c $<

.PHONY:output
output:
	mkdir -p mymath_lib/include
	mkdir -p mymath_lib/lib
	cp -f *.h mymath_lib/include
	cp -f *.so mymath_lib/lib

.PHONY:clean
clean:
	rm -rf *.o *.so mymath_lib

gcc默认是动态链接的,但个别库,如果你只提供.a,gcc也是没有办法,只能局部性的把你指定的.a,进行静态链接,其他库正常动态链接,如果加上-static,就必须要.a
在这里插入图片描述
运行动态库的方法:
1.直接安装到系统中
在这里插入图片描述

2.通过软连接,查找动态库
3.LD_LIBRARY_PATH,使用环境变量的方式,让系统找到自己的动态库
4.直接更改系统关于动态库的配置文件
在这里插入图片描述
动态库加载的原理

gcc -fPIC -c XXX.c

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

索隆43

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值