Linux05系统编程

Posted by 川川的博客 on May 8, 2025

Linux系统编程

image-20250615193853491

man man帮助手册

man 2 fopen()

注意:

  • 指针类型的返回值,主调函数需要释放内存

  • 系统调用返回值不实现功能,只用来处理报错
  • 指针类型的参数,主调函数开辟空间把地址做参数传递

文件

文件类型:

  1. 普通文件
  2. 目录文件
  3. 软链接
  4. 字符设备文件 鼠标
  5. 块设备文件 磁盘
  6. 管道文件 通信
  7. socket 网络

全局变量 errno ->perror();

fopen(path,mode)

image-20250615215516762

库函数

FILE* fp = fopen(argv[1],”a+”);

mode:
	"a"  只写追加-》默认从文件结尾写入
	"a+" 读写追加  打开时ptr处于文件开始base,写入时处于文件结尾
日志系统

追加模式打开文件:

fread(buf,1,1024,fp);
puts(buf);
fseek(fp,0,SEEK_SET);//fp.ptr移到开头
printf("loc=%ld",ftell(fp));//打印fp.ptr指向位置
fwrite("hello",1,1024,fp);//追加模式,ptr还是处于末尾写入

image-20250615220756857

chmod(path,mode_t)

修改目录权限

#include <func.h>
int main(int argc,char* argv[])
{
	//.chmod  dir1 777
	ARGS_CHECK(argc,3);
	mode_t mode;
	sprintf(argv[2],"%o",&mode);
	int ret = chmod(argv[1],mode);
	ERROR_CHECK(ret,-1,"chmod");
	
}

getcwd(buf,size)

获取当前工作目录

  • buf不为空,返回buf

  • 如果buf是空指针,size=0,自动申请堆空间返回

char buf[1024]={0};
char* ret = getcwd(buf,sizeof(buf));
printf("getcwd=%s ",getcwd(NULL,0));

chdir(path)

修改工作目录

  • cwd是进程属性,shell父进程,getcwd子进程,chdir修改的子进程工作目录
./chdir dir1
ARGS_CHECK(argc,2);
int ret = chdir(argv[1]);
ERROR_CHECK(ret,-1,"chdir");

mkdir(path,mode_t)

创建目录

./mkdir dir1 777
ARGC_CHECK(argc,3);
mode_t mode;
sprintf(argv[2],"%o",&mode);
int ret = mkdir(argv[1],mode);
ERROR_CHECK(ret,-1,"mkdir");

rmdir(path)

删除目录

./rmdir dir1
ARGC_CHECK(argc,2);
int ret = rmdir(argv[1]);
ERROR_CHECK(ret,-1,"rmdir");

目录流

  • 是目录文件在内存中的缓冲区

image-20250615231932444

opendir(path)

打开目录流

DIR* dirp = opendir(argv[1]);
ERROR_CHECK(dirp,NULL,"opendir");

readdir(dirp)

读取目录流

  • 返回值结点指针struct dirent*

  • image-20250615234257363

    d_type

    image-20250617194542058

struct dirent* pdirent = readdir(dirp);

遍历目录ls

// ./ls dir
ARGC_CHECK(argc,2);
DIR* dirp = opendir(argv[1]);
ERROR_CHECK(dirp,NULL,"opendir");

errno = 0;
struct dirent* pdirent;
while((pdirent = readdir(dirp)) != NULL){
	printf("ino = %ld  reclen=%d type=%d name=%s\n",
		pdirent->d_ino,pdirent->d_reclen,pdirent->d_type,pdirent->d_name);
		
}
if(errno){
	perror("readdir");
	exit(1);
}
closedir(dirp);


telldir(dirp)

image-20250615235216442

  • readdir(dirp)后,ptr指向结点的下一个结点

获取ptr的位置

long loc = telldir(dirp);

seekdir(dirp,long)

把ptr定位到loc位置

seekdir(dirp,loc);

rewinddir(dirp)

把ptr回到开始位置

rewinddir(dirp)

stat(path,statbuf)

stat函数:取得指定文件的文件属性,文件属性存储在结构体stat里

  • struct stat* statbuf

  • st_mode

  • getpwuid()获取用户id
  • getgrgid()获取组id

  • ctime() gmtime() localtime() 获取时间
//实现./ls -al dir
#include <func.h>
int main(int argc,char *argv[]){
	ARGC_CHECK(argc,3);
	DIR* pdir = opendir(argv[2]);
	ERROR_CHECK(pdir,NULL,"opendir");
	
	char str[11]={0};
	memset(str,'-',sizeof(str)-1);
    //文件类型
    if(S_ISREG(sbuf.st_mode))  str[0] = '-';
    if(S_ISDIR(sbuf.st_mode))  str[0] = 'd';
    if(S_ISCHR(sbuf.st_mode))  str[0] = 'c';
    if(S_ISBLK(sbuf.st_mode))  str[0] = 'b';
    if(S_ISFIFO(sbuf.st_mode)) str[0] = 'p';
    if(S_ISLNK(sbuf.st_mode))  str[0] = 'l';
    if(S_ISSOCK(sbuf.st_mode)) str[0] = 's';

    //本用户的文件权限
    if(sbuf.st_mode & S_IRUSR) str[1] = 'r';
    if(sbuf.st_mode & S_IWUSR) str[2] = 'w';
    if(sbuf.st_mode & S_IXUSR) str[3] = 'x';

    //本用户的组的文件权限
    if(sbuf.st_mode & S_IRGRP) str[4] = 'r';
    if(sbuf.st_mode & S_IWGRP) str[5] = 'w';
    if(sbuf.st_mode & S_IXGRP) str[6] = 'x';

    //其他用户的文件权限
    if(sbuf.st_mode & S_IROTH) str[7] = 'r';
    if(sbuf.st_mode & S_IWOTH) str[8] = 'w';
    if(sbuf.st_mode & S_IXOTH) str[9] = 'x';

	struct dirent* pdirent;
	struct stat sbuf;
	while((pdirent = readdir(pdir))!=NULL)
	{
		char* name[] = pdirent->d_name;
		stat(name,&sbuf);
		
		//取得日期和时间
		char time[20] = {0};
  		struct tm* tm = localtime(&sbuf.st_atim.tv_sec);
  		sprintf(time, "%2d月  %2d %02d:%02d", tm->tm_mon + 1, tm->tm_mday,
	  			tm->tm_hour + 1,tm->tm_sec);
		
		//drwxrwxr-x 2 liyf liyf 4096 6月  13 12:22 dir
		printf("%s %ld %s %s %ld %s %s\n",str, sbuf.st_nlink, getpwuid(sbuf.st_uid)->pw_name,
        		getgrgid(sbuf.st_gid)->gr_name, sbuf.st_size,time ,name);
	}
	
	if(errno){
		perror("readdir");
		exit(1);
	}
	close(pdir);
}

实现tree命令



int directories = 0,files = 0;

void dfs_print(char* path,int width){
	DIR* pdir = opendir(path);
	ERROR_CHECK(pdir,NULL,"opendir");
	errno = 0;
	struct dirent* pdirent;
	while((pdirent = readdir(pdir))!=NULL){
			char* name = pdirent->d_name;
			//if(strcmp(name,".")==0||strcmp(name,"..")==0){
			//	continue;
			//}
			if(name[0]=='.'){
				contiune;
			}
			//缩进
			for(int i =0 ;i<width;i++){
				if(i<width-4)
					printf(" ");
				else
					printf("-");
			}
			
			puts(name);
			if(pdirent->d_type == DT_DIR){
				directories++;
				char director[512];
				sprintf(director,"%s/%s",path,name);
				dfs_print(director,width+4);
			}
			else{
				files++;
			}
			
			
	}
	if(errno){
		perror("readdir");
		exit(1);
	}
	closedir(pdir);
	

}

./tree dir

int main(int argc,char* argv[]){
	ARGC_CHECK(argc,2);
	puts(argv[1]);
	
	dfs_print(argv[1],4);
	
	printf("directories=%d,files=%d\n",directories,files);


	return 0;
}

strlen()读到第一个为零位置结束

read 磁盘文件 读到字节<=count,每次read,pos后移,若缓冲区无数据,返回0读完,

read 设备文件 若缓冲区无数据,进程陷入阻塞,ctrl+d文件终止,阻塞不占用cpu

读写二进制文件

image-20250614172233281

image-20250614173410041

fread/fwrite对比read/write

image-20250614174646905

文件映射 mmap

image-20250614182252658

lseek

image-20250614183907920

FILE和文件对象

image-20250615155615785

重定向

重定向stdout,更改1号fd引用的文件对象

dup复制文件描述符 选择最小可用文件描述符

image-20250615162719642

image-20250615163934427

image-20250615164331906

有名管道

mkfifo 1.pipe 创建管道 文件大小永远是0

一读一写,两端都执行,只执行一端会阻塞

open会引发阻塞,等到对端也被open了,才会恢复就绪

image-20250615171952353