#Linux中的GCC编程# 标准IO与系统IO

基于C,进一步研究 linux内核函数,系统级别的函数

201708xx

1、缓存

缓存是为了解决速度差的问题。

1.1 IO缓存(标准IO)

  1. 全缓存
    磁盘文件。
    刷新方式:(1)全缓存 8192字节,全缓存满了,会刷新;(2)fflush(文件流指针FILE*)。(3)fclose

  2. 行缓存
    标准输出stdout,标准输入 stdin。stdout—> printf();
    刷新方式:(1)’\n’ ,将内容 物理输出到屏幕;(2)行缓存满了,1024字节;(3)fflush(stdout)。

  3. 无缓存
    标准错误流stderr。
    刷新方式:无刷新。
    直接输出:
    (1)perror(“XXX”);//会有一个success在后面
    (2)fprintf(stderr,“XXX\n”);
    (3)exit(0);//#include <stdlib.h> 执行时,会刷新IO (直接输出)
    _Exit(0);//#include <stdlib.h> 执行时,会刷新IO (直接输出)
    _exit(0);//#include <unistd.h> 不刷新IO(不会输出)

  4. 缓存操作函数
    setbuf(stdin,buffer);//更改键盘输入 存储的位置

#include <stdio.h>
void setbuf( FILE * stream, char* buf);//
void setbuffer(FILE *stream, char *buf, size_t size);
void setlinebuf(FILE *stream);
int setvbuf(FILE *stream, char *buf, int mode, size_t size);//更改流属性

2、标准IO与系统IO

2.1 标准IO默认采用了缓冲机制

  1. 标准输入输出IO。头文件为“stdio.h”。
  2. 以fopen为例,man fopen命令查看信息。
  3. 打开文本(放到内存中)。
    fopen: 打开一个文件,
    建立了一个缓冲区(读写模式下将建立两个缓冲区),
    并创建了一个包含文件和缓冲区相关数据的数据结构FILE。
  4. 操作文本。
    可以操作二进制文件的是:fread fwrite
    可以操作字符文件的是:fgets fputs fgetc fputc fscanf fprintf
    一次读取的过程中,fscanf遇到空格和换行时结束,注意空格时也结束。这与fgets有区别,fgets遇到空格不结束。
  5. 关闭文本。
    fclose:关闭文件并刷新缓存。将内存中的文本数据放到本地。
#include <stdio.h>
FILE *	fopen(const char *path, const char *mode);
FILE *	fdopen(int fd, const char *mode);//重新打开系统IO/文本IO返回的fd文件描述符,得到新的文件指针fp。
FILE *	freopen(const char *path, const char *mode, FILE *stream); //重定向//用于更改与标准文本流(stderr、stdin或stdout)关联的文件。
size_t 	fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t	fwrite(const void *ptr, size_t size, size_t nmemb,  FILE *stream);
int	fclose(FILE *stream);

2.2 系统IO,也叫文件IO,低级IO。无缓存

  1. 以open为例,通过man 2 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);
int 	creat(const char *pathname, mode_t mode);
int 	openat(int dirfd, const char *pathname, int flags);
int 	openat(int dirfd, const char *pathname, int flags, mode_t mode);
//open(), openat(), and creat() 返回文件描述符fd或者-1(失败)

#include <unistd.h> //unix standard
//这里的ssize 相当于int,这里是用于跨平台,兼容性。
ssize_t 	read(int fd, void *buf, size_t count);//成功返回读取的字节数 //失败返回-1
ssize_t 	write(int fd, const void *buf, size_t count);//失败返回-1
int 		close(int fd);

#include <sys/ioctl.h>
int 	ioctl(int fd, unsigned long request, ...);

#include <unistd.h>
#include <fcntl.h>
int 	fcntl(int fd, int cmd, ... /* arg */ );//可用于追加文件的权限。等等。

#include <sys/types.h>
#include <unistd.h>
off_t 	lseek(int fd, off_t offset, int whence);

3、一些测试代码

3.1 将字符串的字母一个一个打印出来,要求不换行。

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
void delay(int time)
{
 	usleep(time*10000);
}
int main(int argc,char* argv[])
{
 	if(argc<2)
 	{
  		printf("缺少\n");
  		return -1;
 	}
/*
 	if(argc!=2)
 	{
  		char* p="参数不够";
  		fprintf(stderr,"%s\n",p);//标准错误流,无缓存,不用刷新
  		//或者  
  		perror("参数不够\n");//标准错误流,无缓存,不用刷新
  		return -1;
 	}
*/
	 int i=0;
 	while(argv[1][i])
 	{
  		printf("%c ",argv[1][i]);
  		fflush(stdout);//fflush刷新行缓存(stdout)
  		delay(10);
  		i++;
	 }
 	printf("\n");
 	return 0;
}

运行效果:字符串成员一个一个的被打印出来,(不是一下子被打印出来)。

kshine@kshine-virtual-machine:~/桌面/lsd/0817$ gcc demo1.c -o D1 -Wall
kshine@kshine-virtual-machine:~/桌面/lsd/0817$ ./D1
缺少
kshine@kshine-virtual-machine:~/桌面/lsd/0817$ ./D1 Kshine2017
K s h i n e 2 0 1 7 

3.2 系统IO(文本IO)操作

  1. 打开指定的文件。
  2. 向其中写入我的幸运数字23,此时文件的偏移指针已经后移。
  3. 通过lseek,将偏移指针移动到前面。
  4. 再次读取刚写入的数据。
  5. 最后关闭文件。
//标准IO库函数
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//系统io
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
int main(int argc, char** argv)
{
 	if(argc<2)
 	{
  		printf("输入出错\t");
  		fprintf(stderr,"%s\n",strerror(errno));
  		return 0;
 	}
	 int fd = open(argv[1],O_RDWR | O_TRUNC |O_CREAT ,0664);
 	//-------------
 	int value=23;//我的幸运数字23
	 if(write(fd,&value,sizeof(int))==-1)
 	{
  		printf("写 出错\t");
  		fprintf(stderr,"%s\n",strerror(errno));
  		return 0;
 	}
 	printf("write success!\n");
 	//------------
 	int value2=0;
 	//lseek(fd,-2,SEEK_CUR);//方法一:在当前的位置的基础上,向前移动2位。
 	lseek(fd,0,SEEK_SET);//方法二:直接设置偏移指针到文件开头。
 	printf("offset success!\n");
 	if(read(fd,&value2,sizeof(int))==-1)
 	{
  		printf("读错误\t");
  		fprintf(stderr,"%s\n",strerror(errno));
  		return 0;
 	}
 	printf("read success!\n");
 	printf("the value is : %d\n",value2); 
 	close(fd);
 	return 0;
}

运行结果:

kshine@kshine-virtual-machine:~/桌面/lsd/0817$ gcc demo2.c -o D1 -Wall
kshine@kshine-virtual-machine:~/桌面/lsd/0817$ ./D1 text2
write success!
offset success!
read success!
the value is : 23

3.3 系统IO+标准IO,向文件中写入ip和port等式信息,提取出数值信息。

要求通过 系统IO,分解出192.168.1.1存入 第一个字符数组中,分解出8080 存入第二个字符数组中。最后打印输出。

  • 先通过系统IO,向文件中写入信息。
  • 再通过fdopen,转到标准IO的操作。
  • 利用标准IO,将偏移指针移回文件开头。
  • 读取文件信息,并做提取处理。
  • 关闭文件
//标准库
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//系统库
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
int main(int argc,char* argv[])
{
 	//程序执行命令,无后接的字符串
 	if(argc>=2)
 	{
  		printf("执行命令错误\n");
  		//fprintf(stderr,"%s\n",strerror(errno));
  		return 0;
 	}
 	//用户输入
 	int i=0;
 	char str1[30]="";
 	char str2[30]="";
 	printf("请输入字符串1\n");//行缓存,\n刷新输出
 	//scanf("%s%s",str1,str2);
 	//gets(str1);//编译告警:gets函数中,没有指定接受的长度,可能会超出存储范围。不建议使用。
 	fgets(str1,30,stdin);
 	printf("请输入字符串2\n");
	 //gets(str2);
 	fgets(str2,30,stdin);
 	//系统IO的操作---------------------------------------
 	//1、打开文件
 	//int open(const char *pathname, int flags, mode_t mode);
 	int fd = open("hw1",O_RDWR | O_CREAT | O_TRUNC,0664); //通过文件符打开 //权限 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH
 	printf("open success!\n");//行缓存 通过\n 刷新输出
 	//2、写入数据  
 	if(write(fd,str1,sizeof(char)*30) == -1 || write(fd,str2,sizeof(char)*30) == -1 )
 	{
  		printf("写出错!\n");
  		fprintf(stderr,"%s\n",strerror(errno));
  		return 0;
 	}
 	printf("write success!\n");
 	//3、偏移文件操作指针的位置
 	//lseek(fd,0,SEEK_SET);
 	FILE* fp =fdopen(fd,"r+");
    	//r+和w+都是读写,但是w+会清空已有文件
 	fseek(fp,0,SEEK_SET);
 	//4、读取数据
	 i=0;
 	char ch=0;
 	int flag=0,count=0;//用于切换存储的数组
 	for(;;)
 	{
  		//读取单个字符
  		if(read(fd,&ch,sizeof(char)) == 0 )
  		{
   			break;
  		}
  		if((ch <= '9'&& ch >= '0')|| ch== '.')//如果是数字或者.
  		{
   			if(ch == '.' && count>=0  )//记录‘.’的个数
   			{
    				count++;
  			 }
  			 if(flag==0)//第一个字符串存储
   			{
    				str1[i]=ch;
    				i++;
    				continue;
   			}
   			if(flag >= 1)//1 第二个字符开始 2
   			{
    				flag=2;
    				str2[i]=ch;
    				i++;
    				continue;
   			}
   			continue;
  		}
  		//已经经过3个. 到这里还不是数字
  		else if(count==3)
  		{
  			 count=-10;//结束计数
   			str1[i]='\0';
   			flag=1;//切换到字符串2
   			i=0;  
  		}
  		if(flag==2)//已经在str2中写了数字了,这里不是数字,则端口的数值结束
  		{
   			str2[i]='\0';
   			break;
  		}
 	}
 	printf("read success!\n");
 	//5、关闭文件
 	close(fd);
 	printf("close success!\n");
 	//6、输出
 	printf("%s\n",str1);
 	printf("%s\n",str2);
 	return 0;
}

运行结果:

kshine@kshine-virtual-machine:~/桌面/lsd/0817$ gcc homework1.c -o D1 -Wall
kshine@kshine-virtual-machine:~/桌面/lsd/0817$ ./D1
请输入字符串1
IP = 192.168.1.1
请输入字符串2
PORT = 8080
open success!
write success!
read success!
close success!
192.168.1.1
8080

3.4 系统IO,实现copy功能

要求文件名1,文件名2 从main的参数传入。

//标准库
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//系统库
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
int main(int argc,char* argv[])
{
        //程序执行命令
        if(argc<3)
        {
                printf("执行参数不够\n");
                //fprintf(stderr,"%s\n",strerror(errno));
                return 0;
        }       
        //系统IO的操作---------------------------------------
 	//1、打开文件
 	int fd1 = open(argv[1],O_RDONLY,0664);//文件1,打开 读取 
 	printf("open file1 success!\n");
	int fd2 = open(argv[2],O_WRONLY | O_CREAT | O_TRUNC,0664); //通过文件符打开//权限 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH
	printf("open file2 success!\n");//行缓存 通过\n 刷新输出
 	//2、单字符搬运
 	char ch=0;
 	while(1)
 	{
  		//读取单个字符
		if(read(fd1,&ch,sizeof(char)) == 0 )
                {
                        break;
                }
  		write(fd2,&ch,sizeof(char));
 	}
        printf("copy complete!\n");
	//3、关闭
 	close(fd1);
 	close(fd2);
	return 0;
}

3.5 重定向

将九九乘法表打印到文件中,要求使用重定向。
重定向有两种方式:

  1. freopen
  2. dup2
//标准IO库函数
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//系统io
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
int main(int argc ,char** argv)
{
 	if(argc!=2)
 	{
  		fprintf(stderr,"命令参数个数错误\n");
  		return 0;
 	}
 	//创建文件
	 int fd=creat(argv[1],0664);//int creat(const char *pathname, mode_t mode);
 #if 1
 	//重定向
 	if(freopen(argv[1],"w",stdout)==NULL)
 	{
  		printf("重定向失败\n");
  		return 0;
 	} 
 #endif
 #if 0
 	/* 重定向 */  
        if (-1 == dup2(fd,STDOUT_FILENO) )
        {  
                printf("can't redirect fd error\n");  
                exit(1);  
        }  
 #endif
 	//输出
 	int i=1,j=1;
 	printf("九九乘法表:\n");
 	for(i=1;i<=9;i++)
 	{
  		for(j=1;j<=9;j++)
  		{
   			printf("%dx%d=%d\t",i,j,i*j);
  		}
  		printf("\n");
 	}
 	//还原重定向
 #if 1
 	if(freopen("/dev/tty","w",stdout)==NULL)
        {
                printf("重定向失败\n");
                return 0;
        }
 #endif
 #if 0
 	/* 恢复stdout */  
        if (-1 != dup2(fd,STDOUT_FILENO) ) 
        {  
                printf("recover fd ok \n");  
                write(STDOUT_FILENO,"stdout\n",7);   /* 恢复后,写入stdout应该向屏幕输出 */  
        }  
 #endif
 	//再次输出
 	printf("write ok \n");
 	//关闭
 	close(fd);
 	return 0;
}

运行结果:

kshine@kshine-virtual-machine:~/桌面/lsd/0817$ gcc homework3.c -o D1 -Wall
kshine@kshine-virtual-machine:~/桌面/lsd/0817$ ./D1
命令参数个数错误
kshine@kshine-virtual-machine:~/桌面/lsd/0817$ ./D1 jjcfb
write ok 
kshine@kshine-virtual-machine:~/桌面/lsd/0817$ cat jjcfb 
九九乘法表:
1x1=1 1x2=2 1x3=3 1x4=4 1x5=5 1x6=6 1x7=7 1x8=8 1x9=9 
2x1=2 2x2=4 2x3=6 2x4=8 2x5=10 2x6=12 2x7=14 2x8=16 2x9=18 
3x1=3 3x2=6 3x3=9 3x4=12 3x5=15 3x6=18 3x7=21 3x8=24 3x9=27 
4x1=4 4x2=8 4x3=12 4x4=16 4x5=20 4x6=24 4x7=28 4x8=32 4x9=36 
5x1=5 5x2=10 5x3=15 5x4=20 5x5=25 5x6=30 5x7=35 5x8=40 5x9=45 
6x1=6 6x2=12 6x3=18 6x4=24 6x5=30 6x6=36 6x7=42 6x8=48 6x9=54 
7x1=7 7x2=14 7x3=21 7x4=28 7x5=35 7x6=42 7x7=49 7x8=56 7x9=63 
8x1=8 8x2=16 8x3=24 8x4=32 8x5=40 8x6=48 8x7=56 8x8=64 8x9=72 
9x1=9 9x2=18 9x3=27 9x4=36 9x5=45 9x6=54 9x7=63 9x8=72 9x9=81

3.6 系统IO,修改已打开的文件的权限

1 ,打开一个文件,权限为读写。如果文件不存在需要touch一个空文件出来。
2 ,通过fcntl 增加 “追加“ 权限。
3 ,追加写入helloworld, 最终文件里有helloworld。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
int main(int argc, char** argv)
{
 	//打开文件
 	int fd = open ( argv[1],O_RDWR,0664);
 	if(fd==-1)
 	{
  		printf("打开失败\n");   
  		return 0;
   	}
 	//修改权限
 	int get_fl=(fcntl(fd,F_GETFL)) | O_APPEND ;
 	//fcntl(fd,F_SETFL,get_fl|O_APPEND);//这样可能会在跨系统的时候,产生二异性
 	//传参的时候,尽量保证传定值
 	fcntl(fd,F_SETFL,get_fl); 
 	//写入
 	char str[]="helloworld";
 	if(write(fd,str,strlen(str))==-1)
 	{
  		fprintf(stderr,"%s\n",strerror(errno));
  		return 0;
 	}
 	//关闭
 	close(fd);
 	return 0;
}

运行结果

kshine@kshine-virtual-machine:~/桌面/lsd/0818$ gcc demo2.c -o main -Wall
kshine@kshine-virtual-machine:~/桌面/lsd/0818$ ./main
打开失败
kshine@kshine-virtual-machine:~/桌面/lsd/0818$ ./main Test
打开失败
kshine@kshine-virtual-machine:~/桌面/lsd/0818$ touch Test
kshine@kshine-virtual-machine:~/桌面/lsd/0818$ ./main Test
kshine@kshine-virtual-machine:~/桌面/lsd/0818$ cat Test 
helloworld

3.7 系统IO,umask和access

使用umask函数将umask屏蔽值修改为:当前你所创建的文件都只写。
使用open 函数创建文件a.txt使文件的权限为rw—x-wx。
使用access判断该文件是否具有可写文件。
如果有可写文件,则使用chmod 将用户的可写文件删除。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
int main(int argc,char* argv[])
{
	//1、umask设置删除的权限信息,都是只写
 		//mode_t umask(mode_t mask);
 	mode_t new_umask;  
 	new_umask=0333;//  
 	umask(new_umask);  
 	printf("已设置权限掩码!\n");  
	//2、使用open 函数创建文件a.txt使文件的权限为rw---x-wx。
 	int fd = open(argv[1],O_CREAT|O_TRUNC|O_RDWR,S_IRUSR|S_IWUSR|S_IXGRP|S_IWOTH|S_IXOTH);
 	close(fd);
 	printf("创建了文件%s,有写的权限\n",argv[1]);
	// system("ls -l");
	//3、使用access判断该文件是否具有可写文件。
 		//int access(const char *pathname, int mode);
	if(access(argv[1],R_OK)==0)
 	{
  		printf("判断,具有写的权限!\n");
 	}
 	else
 	{
  		printf("用户不具有写的权限\n");
 	}
	//4、如果有可写文件,则使用chmod 将用户的可写文件删除。 
 		//int chmod(const char *path, mode_t mode);
 	if(chmod(argv[1],S_IRUSR|S_IXGRP|S_IXOTH)==-1)
 	{
  		fprintf(stderr,"%s\n",strerror(errno));
  		return 0;
 	}
 	printf("已删除可写权限\n"); 
 	system("ls -l");
 	return 0;
}

3.8 通过文件名,判断文件类型

//int stat(const char *path, struct stat *buf);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
int main(int argc,char* argv[])
{
        if(argc!=2)
        {
                fprintf(stderr,"%s\n",strerror(errno));
                return 0;
        }
//定义结构体
 	struct stat  buffer={};//已经初始化
 	//memset(&buf,0,sizeof(struct stat));
//传入文件信息
 	// int stat(const char *path, struct stat *buf);
 //  路径的地址  结构体类型的存储变量
 	if(stat(argv[1], &buffer)==-1)
 /*****************************************
 RETURN VALUE
 On success, zero is returned.  
 On error,     -1 is returned,
 and errno is set appropriately.
***************************************/
 	{
  		fprintf(stderr,"%s\n",strerror(errno));
  		return 0;
 	}
//判断文件信息
 	//buffer.st_mode
 /************************************
 The following POSIX macros are defined to check the file type using the st_mode field:
           S_ISREG(m)  is it a regular file?
           S_ISDIR(m)  directory?
           S_ISCHR(m)  character device?
           S_ISBLK(m)  block device?
           S_ISFIFO(m) FIFO (named pipe)?
           S_ISLNK(m)  symbolic link? (Not in POSIX.1-1996.)
           S_ISSOCK(m) socket? (Not in POSIX.1-1996.)
 ************************************/ 
 	if(S_ISREG(buffer.st_mode))
                printf("a regular file\n");
        if(S_ISDIR(buffer.st_mode))
                printf("directory\n");
        if(S_ISCHR(buffer.st_mode))
                printf("character device\n");
        if(S_ISBLK(buffer.st_mode))
                printf("block device\n");
        if(S_ISFIFO(buffer.st_mode))
                printf("FIFO (named pipe)\n");
        if(S_ISLNK(buffer.st_mode))
                printf("symbolic link\n");
        if(S_ISSOCK(buffer.st_mode))
                printf("socket\n");
        return 0;
}

3.9 显示指定目录下及其子目录下的所有文件名

使用递归调用

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <dirent.h>
//判断是不是目录
int judge_dir(char *name);
//展示目录名或者文件名
void kshine_ls(char* name);
int main(int argc,char* argv[])
{
 	if(argc!=2)
 	{
  		fprintf(stderr,"%s\n",strerror(errno));
  		return 0;
 	}
 	kshine_ls(argv[1]);
 	return 0;
}
void kshine_ls(char* name)
{
 	printf("---- 进入  目录 ----\n");
 	//DIR *opendir(const char *name);  //成功返回目录指针,失败返回NULL,有errno
 	//struct dirent *readdir(DIR *dirp);  //成功返回指针,结尾或者出错返回NULL
 	//void rewinddir(DIR *dirp);  //成功返回0,出错返回-1
 	//int closedir(DIR *dirp);  //成功返回0,出错返回-1
//打开目录(根据目录名,定义一个目录指针)
 	DIR* dir_p = opendir(name);
 	if(dir_p == NULL)
 	{
  		fprintf(stderr,"%s\n",strerror(errno));
  		return;
 	}
//读取目录(根据目录指针dir_p ,返回d_p指针)
 	struct dirent  *d_p;
 	while(1)
 	{
  		d_p = readdir(dir_p);
  		if(d_p == NULL)
  		{
  			 break;
 		 }
 		//显示目录名称 
 		//d_name[256]; /* filename */
  		printf("%s\n",d_p->d_name);
  		if(strcmp(d_p->d_name,".") == 0 || strcmp(d_p->d_name , "..")==0)
 		 {
   			continue; 
  		}
  		if(judge_dir(d_p->d_name) == 1)//如果是目录
 		 {
   			kshine_ls(d_p->d_name); //递归调用,用于显示子目录的文件名
  		}
	 }
//关闭目录
 	closedir(dir_p);
 	printf("-------------------\n\n");
}
int judge_dir(char *name)
{
 //定义结构体
        struct stat     buffer={};//已经初始化
//传入文件信息
        // int stat(const char *path, struct stat *buf);
        //路径的地址    结构体类型的存储变量
        if(stat(name, &buffer)==-1)
        {
               // fprintf(stderr,"%s\n",strerror(errno));
               // return 0;
        }
//判断文件信息
        if(S_ISDIR(buffer.st_mode))
               return 1;// printf("directory\n");
 	else
 	return 0;
}

运行结果:
3.9显示目录结构

更规范的写法如下:

//递归打印路径
#include <dirent.h>
#include<stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
void show_name(char* cwd);
int main(int argc,char** argv)
{
 	if(argc != 2)
 	{
  		fprintf(stderr,"参数不够\n");
  		return ;
 	}
 	show_name(argv[1]);
    return 0;
}
void show_name(char* cwd)
{
 	DIR* dir_t = opendir(cwd);
 	if(dir_t == NULL)
 	{
  		return ;
 	}
 	chdir(cwd);
 	struct dirent* dirent_t = NULL;
 	while(1)
 	{
  		if((dirent_t = readdir(dir_t)) == NULL)
  		{
   			break;
  		}
  		if(strcmp(dirent_t -> d_name,".")==0 || strcmp(dirent_t->d_name,"..") == 0)
 		{
   			continue;
  		}
  		if(dirent_t -> d_type == DT_DIR)
  		{
   			printf("目录:%s\n\n\n",dirent_t->d_name);
   			show_name(dirent_t -> d_name);
   			chdir("..");
  		}
  		printf("I——NODE:%ld\t文件名:%s\n",dirent_t->d_ino,dirent_t->d_name);
 	}
}

3.10 stat 函数与 lstat 函数的区别

在调用执行文件时,后面接普通文件和link文件,可以看到两者区别。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <dirent.h>
//软连接,硬连接
//stat   函数与 lstat 函数的区别: 
//当一个文件是符号链接时,lstat 函数返回的是该符号链接本身的信息;而 stat 函数返回的是该链接指向文件的信息。
int main(int argc,char* argv[])
{	
	//保存访问前的时间
 	struct stat buf_save={};
 	if(stat(argv[1],&buf_save)==-1)   //int stat(const char *path, struct stat *buf);
 	{
 	 	fprintf(stderr,"%s\n",strerror(errno));
  		return 0;
 	}
//打开文件,写入hello
 	char str_hello[]="hello";
 	int fd = open(argv[1],O_WRONLY,S_IRWXU)
 	if(write(fd,str_hello,strlen(str_hello))==-1)
 	{
  		fprintf(stderr,"%s\n",strerror(errno));
 	}
 //int utime(const char *filename, const struct utimbuf *times);
// struct utimbuf timebuf={};
// time_t t =time(NULL);
// struct tm *p= gtime(&t);
//
// int link(const char *oldpath, const char *newpath);
// char *str="_link";
 	char temp1[20]="";
 	strcpy(temp1,argv[1]);
// strcat();
// link(argv[1], strcat(argv[1],str)); 
//
//stat 查看链接的文件
//lstat 本身
 	struct stat buf={};
 	stat(argv[1],&buf);
 	printf("stat的st_ino是 %ld\n",buf.st_ino);
 	struct stat lbuf={};
 	lstat(argv[1],&lbuf);
 	printf("lstat的st_ino是 %ld\n",lbuf.st_ino);
 	return 0;
}

3.11 获取 当前可执行程序 的工作路径并打印输出,然后在当前路径下修改创建文件的默认权限`为所有用户只能只读并创建一个文件

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <dirent.h>
int main(int argc ,char * argv[])
{
//获取当前路径
 	printf("1、获取当前工作路径------\n\n");
	//char *getcwd(char *buf, size_t size);
 	char buf[50]="";
 	getcwd(buf,50*sizeof(char));
 	printf("使用getcwd()测得的工作路径是:\n");
 	printf("%s\n",buf); 
// char *getwd(char *buf);
	char buf1[50]="";
	getwd(buf1);
	printf("使用getwd()测得的工作路径是:\n");
	printf("%s\n",buf1);
	//char *get_current_dir_name(void);
	char* buf2=get_current_dir_name();
	printf("使用get_current_dir_name()测得的工作路径是:\n");
	printf("%s\n",buf2);
//调用系统system();
 	printf("使用PWD测得的工作路径是:\n");
 	system("pwd");
//2、设置umask
 	printf("\n\n2、设置umask值,限制创建 只能是-w--w--w-\n\n");
 	mode_t modenew=0555;
 	umask(modenew);
 	printf("已设置umask=%o\n\n",modenew);
//3、创建文件
 	printf("3、创建文件,并查看文件属性\n\n");
 	int fd =open(argv[1],O_CREAT|O_TRUNC,0664);
 	close(fd);
 	system("ls -l");
 	return 0;
}

运行结果:

3.11

3.12 实现自己的一个myshell,同时把执行的命令结果重定向输出到文件

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <dirent.h>
//    argv[0]  argv[1]  argv[2]
//   ./main     ls     -l
int main(int argc,char **argv)
{
//1、接受shell命令
 	char buffer[20]="";
 	if(argc>=2)
 	{
		int i=1;
		int len=0;
		strcpy(buffer,argv[1]);
		len=strlen(argv[1]);
		buffer[len]=' ';//用空格分隔
		for(i=2;i<=argc-1;i++)
  		{
   			strcat(buffer,argv[i]);
   			len=strlen(buffer);
   			buffer[len]=' ';//用空格分隔 
  		}
  		printf("\n\n----------得到的命令字符串%s-----------\n",buffer);
	}
//2、重定向
	//保存,int dup(int oldfd);
	int save_val=dup(1);//1 stdout
	//重定向,int dup2(int oldfd, int newfd);
	int res = dup2(1,"h3out.txt");
	if(res==-1)
	{
		fprintf(stderr,"%s\n",strerror(errno));
		return 0;
	}
//3、执行命令
	system(buffer);
	printf("-------------------------------------\n\n");
	return 0;
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Kshine2017/article/details/85336176