0
点赞
收藏
分享

微信扫一扫

OSI 七层模型和TCP/IP 四层模型的区别

yongxinz 2024-09-26 阅读 16

Linux文件I/O

文件结构

在这里插入图片描述

创建目录

  1. 系统分配一个inode和至少一个block
  2. inode记录该目录属性,指向block
  3. block记录该目录下相关联的文件或目录的inode编号和名字

创建文件

  1. 系统分配至少一个inode和与文件大小相对应数量的一个block
  2. inode记录该目录属性,指向block

读取文件流程

  1. 读取目录或文件
  2. 例读取/home下的test.c
  3. 首先根目录的inode编号固定为0
  4. 通过根目录的inode编号找到其inode结构体,通过inode结构体找到其block
  5. 目录的block内容为该目录下的文件inode号与文件名字的表格
  6. 根据文件test.c名字在目录的block找到test.c对应的inode编号,通过该编号就可以找到test.c的内容,进而完成文件内容读取

文件的基本操作

概念补充

文件描述符
文件权限

在这里插入图片描述

系统调用

open系统调用
接口代码
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

int open(const char* pathname,int flags,[mode_t mode]);
参数解释
  • pathname: 字符指针,指向文件路径及文件名
  • flags: 整数形参,定义以何种方式访问文件
    • O_RDONLY: 只读打开文件
    • O_WRONLY: 只写打开文件
    • O_RDWR: 读写打开文件
    • O_CREATE: 按mode中给出的访问方式创建文件
  • mode: 可选参数,只有flags为O_CREAT才生效,表示给文件赋予何种权限
    • 常用数字代表如:0644 ==> -rw-r--r--
实例代码
//参考下方汇总
write系统调用
接口代码
#include <unistd.h>

ssize_t write(int fileds,const void* buffer,size_t n);
参数解释
  • fileds: 文件描述符
  • buffer: 缓冲区
  • n: 从缓冲区写入到文件的字节数
实例代码
#include <unistd.h>
#include <stdlib.h>

int main()
{
    if((write(1,"Here is come data\n",18)) != 18)
        write(2,"A write error has occurred on file description 1\n",46);
    exit(0);
}
read系统调用
接口代码
#include <unistd.h>

ssize_t read(int filedes,void* buffer,size_t nbytes);
参数解释
  • filedes: 之前opencreate调用返回的文件描述符
  • buffer: 指向数组或结构的指针
  • nbytes: 从文件中读取的字节数
实例代码
#include <unistd.h>
#include <stdlib.h>

int main()
{
    char buffer[128];
    int nread;
    nread = read(0,buffer,128);
    if(nread == -1)
        write(2,"A read error has occurred\n",26);
    if((write(1,buffer,nread)) != read)
        write(2,"A write error has occurred\n",27);
    exit(0);
}
create系统调用
接口代码
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int creat(const char* pathname,mode_t mode);
参数解释
  • pathname: 文件路径名
  • mode: 为赋予创建文件的访问权限
实例代码
//参考下方汇总
close系统调用
接口代码
#include <unistd.h>

int close(int filedes);
参数解释
  • filedes: 文件描述符
实例代码
//参考下方汇总
综合应用
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

int main()
{
	int in,out;
    // 源文件路径
	char* inPath = "test.txt";
    // 目标文件路径
	char* outPath = "out.txt";
    // 定义缓冲区
	char buffer[1024] ={0};
    // 以只读方式打开文件
	in = open(inPath,O_RDONLY);
    // 以rw-r--r--打开文件
	out = open(outPath,0644);
    // 输出对应文件描述符
	printf("in = %d,out = %d\n",in,out);
	if(in == -1) exit(1);
	
	// 如果目标文件不存在,就创建
	if(out == -1) out = creat(outPath,0644);
	// 每次成功读取字节数
	ssize_t nread;
	while((nread = read(in,buffer,sizeof(buffer))) > 0)
	{
        // 将缓冲区字节数写入目标文件
		write(out,buffer,nread);
		printf("nread = %ld\n",nread);
		printf("%s\n",buffer);
	}
	
	close(in);
	close(out);
	exit(0);
}

文件状态信息

fstat系统调用
接口代码
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>

int fstat(int fildes, struct stat* buf);
参数解释
  • filedes: 文件描述符
  • stat: 文件状态信息结构体
stat系统调用
接口代码
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>

int stat(const char* path, struct stat* buf);
lstat系统调用
接口代码
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>

int lstat(const char* path, struct stat* buf);
lseek系统调用
接口代码
#include <unistd.h>
#include <sys/types.h>

off_t lseek(int fileds, off_t offset,int start_flag);
参数解释
  • filedes: 参数为文件描述符
  • offset: 参数为表示新位置相对起始位置的字节数
  • start_flag:
    • offset从文件的起始文件开始算,通常值为0
    • offset相对文件读写的当前位置而言,通常值为1
    • offset相对文件尾而言,通常值为2
perror函数
接口代码
#include <stdio.h>
void perror(const char *s);
参数解释
  • 如果s不为空,错误信息会先增加字符串s的内容,再打印错误信息
实例代码
#include <stdio.h>

int sample
{
    int fd;
    fd = open("file",O_RDONLY);
    if(fd == -1)
    {
        perror("Cannot open file");
        return;
    }
}

//运行结果
Cannot open file: No such file or directory
Cannot open file: Interrupted system call
chmod系统调用
接口代码
**#include <sys/stat.h>**

// 修改文件或目录的访问权限
int chmod(const char *path, mode_t mode);
// 改变文件或目录的所有者或组
int chown(const char *path, uid_t owner, gid_t group)
参数解释
  • path: 指定被修改权限的文件
  • mode: 修改的权限设置
  • owner: 用户id
  • group: 组id
实例代码
#include <unistd.h>
#include <sys/stat.h>

int main()
{
    chmod("abc",04764);
    chmod("bcd",S_ISUID|S_IRWXU|S_IRGRP|S_IWGRP|S_IROTH);
    chmod("abc",1000,1000);
    return 0;
}

文件链接

unlike函数
接口代码
#include <unistd.h>

int unlink(const char *pathname);
link函数
接口代码
#include <unistd.h>

int link(const char *path1, const char *path2);
symlink函数
接口代码
#include <unistd.h>

int symlink(const char *path1, const char *path2);

目录操作

opendir函数
接口代码
#include <sys/types.h>
#include <dirent.h>

DIR* opendir(const char* dirname);
readdir函数
接口代码
#include <sys/types.h>
#include <dirent.h>

struct dirent* readdir(DIR* drip);
参数解释
  • drip: 目录流指针
实例代码
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>

int main()
{
    DIR* dir_ptr;
    struct dirent* dirrntp;
    // 打开目录
    if((dir_ptr == opendir("/home")) == NULL)
        perror("can not open /home");
    // 循环读出该目录下每一项
    while((direntp == readdir(dir_ptr)) != NULL)
        printf("%s\n",direntp->d_name);
    close(dir_ptr);
    return 0;
}
telldir函数
接口代码
#include <sys/types.h>
#include <dirent.h>

long int telldir(DIR* dirp);
参数解释
  • drip: 目录流指针

实例代码

#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>

int main()
{
    DIR* dir_ptr;
    struct dirent* dirrntp;
    int dir_loc;
    // 打开目录
    if((dir_ptr == opendir("/home")) == NULL)
        perror("can not open /home");
    // 循环读出该目录下每一项
    while((direntp == readdir(dir_ptr)) != NULL)
    {
        printf("%s\n",direntp->d_name);
        // 获取当前文件流位置
        dir_loc = telldir(dir_ptr);
        printf("%d\n",dir_loc);
    }
    close(dir_ptr);
    return 0;
}
seekdir函数
接口代码
#include <sys/types.h>
#include <dirent.h>

void seekdir(DIR* dirp,long int loc);
参数解释
  • drip: 目录流指针
  • loc: 用来设置指针位置,通过telldir调用获得
closedir函数
接口代码
#incldue <sys/types.h>
#include <dirent.h>

int closedir(DIR* dirp);
综合实例
// Linux下输入文件
$ gcc -o findDir findDir.c
$ ./findDir ../
    
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <locale.h>
#include <stdint.h>
#include <string.h>

#define LINES 200
#define NAMELEN 1024

char fileDir[LINES][NAMELEN];
int front = 0;// 队头指针
int rear = 0;// 队尾指针
char* out = "./ans.txt";// 输出文件
FILE* fq;
void insert(char* str)
{
	strcpy(fileDir[rear++],str);
	
	if(rear % LINES == 0)rear = 0;
}

char* pop()
{
	char* str = fileDir[front];
	front++;
	if(front % LINES == 0)front = 0;
	return str;
}

int empty()
{
	return rear == front ? 1 : 0;
}

void findDir(char* fileNamePath)
{
	DIR* dir;
	struct dirent* dirDetails;
	struct stat buff;
	if((dir = opendir(fileNamePath)) == NULL)
	{
		printf("%s文件目录不存在\n",fileNamePath);
		return;
	}

	// 队列开始,循环判断每一项
	while((dirDetails = readdir(dir)) != NULL)
	{
		char* str1 = ".";
		char* str2 = "..";
		int ren[2];
		ren[0] = strcmp(dirDetails->d_name,str1);
		ren[1] = strcmp(dirDetails->d_name,str2);
		// 过滤当前目录.和父目录..
		if(ren[0] == 0 || ren[1] == 0 )continue;
		// 过滤隐藏文件
		if(dirDetails->d_name[0] == '.')continue;

		char fullPath[1024] = {0};
		strcpy(fullPath,fileNamePath);
		int len = strlen(fullPath);

        // 这一步???
		if(fullPath[len-1] != '/')
		{
			fullPath[len++] = '/';
			fullPath[len] = 0;
		}

		// 拼接得到完整目录文件
		strcat(fullPath,dirDetails->d_name);
		
		if(stat(fullPath,&buff) == -1)
		{
			printf("00000000000000,fullPath =  %s\n",fullPath);
			continue;
		}
		else
		{
			if(S_ISDIR(buff.st_mode))
			{
				strcat(fullPath,"/");// 构建成目录
				insert(fullPath);// 加入队列
			}
			else fprintf(fq,"%s\n",fullPath);// 输出文件内容
		}
	}
	closedir(dir);// 关闭目录流
	if(!empty())
	{
		char* dirPath = pop();
		findDir(dirPath);
	}
}

int main(int argc,char* argv[])
{	
	fq = fopen(out,"w");
	if(argc != 2)
	{
		printf("error卒\n");
		exit(-1);
	}
	findDir(argv[1]);
	fclose(fq);
	printf("结束\n");
	exit(0);
}

文件入口getopt函数

函数原型
#include <unistd.h>

int getopt(int argc, char * const argv[], const char *optstring);
参数
  1. argc: 命令行参数的个数,通常由 main 函数传递给 getopt
  2. argv: 命令行参数的数组,通常由 main 函数传递给 getopt
  3. optstring: 一个字符串,定义了有效选项及其参数的格式。每个字符代表一个选项:
    • 如果字符后面跟有冒号(如 a:),则表示这个选项需要一个参数。
    • 如果字符后面没有冒号(如 b),则表示这个选项不需要参数。
    • 如果 optstring 中包含 ?getopt 会在遇到无效选项时返回 ?
返回值
  • 选项字符: getopt 会返回当前处理的选项字符。如果选项需要一个参数,optarg 会指向这个参数的字符串。
  • -1: 当没有更多选项可以处理时,getopt 返回 -1
全局变量
  • optarg: 指向当前选项的参数。如果当前选项需要一个参数(如 -o value 中的 value),optarg 指向该参数的字符串。如果选项不需要参数,则 optargNULL
  • optind: 在解析选项后,指向 argv 中下一个未处理的参数的位置。它可以用来访问剩余的命令行参数。
  • opterr: 用于控制 getopt 是否输出错误消息。如果 opterr 被设置为 0,getopt 将不会输出错误消息。默认情况下,它的值是 1。
  • optopt: 当遇到无效的选项时,optopt 被设置为无效选项字符。它可以用于自定义错误消息。
示例代码

下面是一个使用 getopt 的简单示例:

#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
    int opt;
    while ((opt = getopt(argc, argv, "a:b::c")) != -1) {
        switch (opt) {
            case 'a':
                printf("Option -a with value %s\n", optarg);
                break;
            case 'b':
                printf("Option -b with value %s\n", optarg ? optarg : "none");
                break;
            case 'c':
                printf("Option -c\n");
                break;
            case '?':
                if (optopt == 'b') {
                    printf("Option -%c requires an argument.\n", optopt);
                } else {
                    printf("Unknown option `-%c'.\n", optopt);
                }
                return 1;
            default:
                abort();
        }
    }
    // Print remaining arguments
    for (int i = optind; i < argc; i++) {
        printf("Remaining argument: %s\n", argv[i]);
    }
    return 0;
}
解释
  • opt = getopt(argc, argv, "a:b::c"):
    • 处理选项 -a,该选项需要一个参数。
    • 处理选项 -b,该选项可以有一个可选参数(冒号后面有两个冒号表示可选)。
    • 处理选项 -c,该选项不需要参数。
  • switch (opt):
    • case 'a': 处理 -a 选项及其参数,打印选项和参数。
    • case 'b': 处理 -b 选项及其参数,如果参数缺失,使用默认值 "none"
    • case 'c': 处理 -c 选项,不需要参数。
    • case '?': 处理无效选项或缺少参数的情况。
  • for (int i = optind; i < argc; i++):
    • 遍历并打印所有剩余的命令行参数。
举报

相关推荐

0 条评论