写在开头,文章仅用于日常学习笔记记录,不具备知识查阅质量。

文件编程:一组相关数据的有序集合。

文件名:这个集合的名字。

文件编程中 Linux 提供了两种函数:

标准IO库(库函数)

例如:printf(“hello\n”);

文件IO(系统调用)

例如:write(1,“word\n”,6);其中6 = 四个字符+一个换行符+一个 ‘\0’

Linux中文件类型:七大类型bcd lsp f

b:块设备文件:硬盘

c:字符设备文件:键盘屏幕鼠标

d:目录文件:eg/home/linux

f:常规文件:.c .bmp

l:链接文件:类似Windows下的快捷方式文件

p:管道文件:用于进程间的通信

s:套接字文件:用于进程间的通信

系统调用是进入内核的唯一路径。

Linux设计思想:

everything is file !

一切皆文件

perror打印系统错位信息

1,库函数标准IO操作文件:丹尼斯·里奇

1,缓存:减少系统调用次数,进而提高效率

2,流

库函数操作文件大致包括:

1,打开 fopen

2,读写 fgetc fputc fgets fputs,fwrite,fread

3,关闭 fclose

fopen
	FILE *fopen(const char *pathname ,const char *mode);
@pathname 文件名 字符串形式
@mode	打开文件的方式
	"r" 打开文件 做读操作
		流定位在文件开头 ps:文件必须存在
	"r+"读写 条件是文件存在
	"w"	只写
		文件存在 截断成0长度
		文件不存在,创建文件
	"w"+读写
	"a" 文件存在时,在末尾写(追加)
		文件不存在,创建文件
	"a+"读 和 追加
		读时,流定位在文件开始
		追加,流定位在文件末尾
返回值:
	成功: FILE*的指针
	失败:NULL并且errno被设置,表明错误原因

其他函数:
	fgetc/fputc 按字符读取写入
	fgets/fputs	按字符串读取写入(按行读写)遇到'\n'停止
	fread/fwrite	按对象读取写入

fgetc
	int fgetc(FILE *stream)
功能:
	从文件中(FILE *文件指针 流指针)读取一个字符
参数:
	@stream 表示读取的文件
返回值:
	成功:返回读取字符的ASCII码,int返回值
	失败:返回EOF
			1,表示到达文件末尾
			2,表示出错
ps:如何判断读取字符是到达文件末尾还是出错???

fputc:
	int fputc(int c,FILE *stream)
	功能:将字符c写到stream对应的文件中
	参数:输出的字符c,流指针
	成功:返回被写入值的ASCII
	失败:返回EOF

fclose(FILE *stream)
功能:断开流 关闭文件对于对的流指针

//打开文件
#include<stdio.h>

int main(int argc, const char *argv[])
{
	FILE *fp = fopen("./hello.c","r");

	if(fp==NULL)
	{
//		printf("open fail");
		perror("open fail");
		return -1;
	}
	return 0;
}
//实现touch功能:
//touch filename#include<stdio.h>
int main(int argc, const char *argv[])
{
	if(argc !=2)
	{
		printf("usage: %s <filename>\n",argv[0]);
		return -1;
	}
	FILE *fp = fopen(argv[1],"w");

	if(fp==NULL) 
	{
//		printf("open fail");
		perror("open fail");
		return -1;
	}
	return 0;
}
//实现cat功能:
#include<stdio.h>
int main(int argc, const char *argv[])
{
	if(argc != 2)
	{
		printf("usage:%s <filename>\n",argv[0]);
		return -1;
	}

	FILE *fp = fopen(argv[1],"r");

	if(fp==NULL) 
	{
//		printf("open fail");
		perror("open fail");
		return -1;
	}
		
	int ret;
	while(EOF !=(ret=fgetc(fp)))
	{
		printf("%c",ret);
	}
	return 0;
}
#include<stdio.h>
int main(int argc, const char *argv[])
{
	int ret;
	while((ret = fgetc(stdin)) != EOF)
	{
		fputc(ret,stdout);
	}
	printf("ret = %d",ret);
	return 0;
}
stdin 标准输入 从键盘输入
stdout	标准输出 在屏幕输出
stderr 
//实现cp命令:
#include<stdio.h>

int main(int argc, const char *argv[])
{
	if(argc!=3)
	{
		printf("err!\n");
		return -1;
	}
	FILE *fp_src=fopen(argv[1],"r");
	FILE *fp_dest=fopen(argv[2],"2");
	if(fp_src==NULL)
	{
		perror("open fail!\n");
		return -1;
	}

	int ret;
	while((ret=fgetc(fp_src)) != EOF)
	{
		int dest = ret;
		fputc(ret,fp_dest);
	}
	fclose(fp_src);
	fclose(fp_dest);

	return 0;
}
fgets/fputs

fgets:
	char *fgets(char *s,int size,FILE *stream);
功能:从文件中读取数据,保存成一个字符串。
参数:
	@s 表示存放字符串的空间的首地址
	@size 表示最多读取size-1的个字符,因为最后一个字符是留给'/0';
	@FILI *stream  
fgets返回条件:
	遇到'\n'
	数组满了;
	到达文件末尾;
成功:返回s
失败:返回NULL1,表示失败
			2,到达文件结尾
//fgets统计文件中有多少个换行:\n
#include<stdio.h>
#include<string.h>

int main(int argc, const char *argv[])
{
	int count = 0;

	if(argc!=2)
	{
		printf("err,less");
		return -1;
	}
	FILE *fp=fopen(argv[1],"r");
	if(fp==NULL)
	{
		perror("open fail");
		return -1;
	}

	char s[20];
//	char *p;
	while(fgets(s,sizeof(s),fp)!=NULL)	
	{
//	p = fgets(s,sizeof(s),fp);
	
	if(s[strlen(s)-1]=='\n');
		count ++;
	}
	fclose(fp);
		
	printf("%d\n",count);
	return 0;
}
fputs:
	int fputs(const char *s,FILE *stream)
功能:
	输出字符串数据s到stream中
参数:
	@s 保存字符串的一块空间的首地址
	@FILE *stream 流指针指向输出的文件
返回值:
	成功:非负数
	失败:EOF

ps:fgets和fputs拷贝“二进制文件”时,会出现问题,其中的\0会导致数据丢失

缓存:

行缓存:缓存1k,1024个字节,主要用于人机交互

刷新条件:

1,遇到\n

2,程序正常结束

3,缓冲区超越刷新

4,fflush强制刷新

#include<stdio.h>
#include<unistd.h>
int main()
{
	printf("123");
	while(1)
		sleep(1);
	return 0;
}
//不会输出123,123存在于输出缓存区
//会一直sleep
//想要输出需要加上\n
#include<stdio.h>
#include<unistd.h>
int main()
{
	int i=0;
	for(i;i<1024;i++)	
	{	
		fputc('a',stdout);
	}
	return 0;
}
//不会输出,缓存区刚好够用
//i<1025时,缓冲区刷新
#include<stdio.h>
#include<unistd.h>
int main()
{
	printf("123");
	fflush(stdout);
	while(1)
		sleep(1);
	return 0;
}
//会输出
//fflush()刷新输出缓冲区

全缓存:缓存区大小4k,主要用于文件处理

对 文件操作一般建立全缓存
刷新条件:
	缓存区满刷新
	程序结束刷新
	fflush强制刷新

无缓存:缓存区大小:0k 一般用于 错误 输出

fflush:

#include<stdio.h>
#include<unistd.h>
int main()
{
	printf("123");
	fflush(stdout);
	while(1)
		sleep(1);
	return 0;
}
//输出缓存区被刷新
//ps:fllush()不能刷新输入缓存区stdin

fread/fwrite:按对象读写

fread:	
	size_t fread(void *ptr,size_t size,size_t nmemb,FILE* stream)
//ps:读到最后没有一个完整对象时,停止读取,fread结束
返回值:
	成功:返回成功读取单位对象大小的个数
	失败:返回0
参数:	
	@ptr 存放数据的一块空间
	@size 单个对象的大小
	@stream 操作到的文件

文件偏移函数::

int fseek(FILE* stream,long offset,int whence);
功能:设置文件指示器位置
参数:
	@stream  操作的文件流指针
	@offset 偏移量
	@whence 基点,有三个默认值
			SEEK_SET 非负数,只能向后偏移
			SEEK_CUR
			SEEK_END
返回值:
	成功 0
	失败 -1 & errno
定位到开头:
	fseek(fp,0,SEEK_SET); <==> rewind()
定位到末尾:
	fseek(fp,0,SEEK_END);

空洞文件:可以强制占用磁盘空间
ftell:获得offset
	long ftell(FILE* stream);
栗子:
//获得文件的长度:
#include<stdio.h>
int main ()
{
	FILE* fp = fopen("xxx","r");
	fseek(fp,0,SEEK_END);
	long len = ftell(fp);
	printf("len of file:%l",len);
	return 0
}

栗子:

创建空洞文件,再创建一个跟空洞文件大小一样的文件:

#include<stdio.h>
int main(int argc, const char *argv[])
{
	FILE *fp = fopen("kong","w");

	fseek(fp,100,SEEK_SET);
	fputc('a',fp);

	long len = ftell(fp);
	FILE *fp1 =fopen("kong2","w");
	int i=0;
	printf("%ld\n",len);
	for(i=0;i<len;i++)
	{
		fputc('b',fp1);
	}
	fclose(fp);
	fclose(fp1);
	return 0;
}

栗子:仿实现迅雷下载,下载前占用空间,根据src文件大小下载dest文件
#include<stdio.h>
#include<stdlib.h>
int main(int argc, const char *argv[])
{
/*
	if(argc!=3)
	{
		printf("err input");
		return -1;
	}
	*/
	FILE *fp_src=fopen("src.txt","r");
	FILE *fp_dest=fopen("download.txt","w");
	if(fp_src==NULL || fp_dest==NULL)
	{
		perror("err!");
		return -1;
	}
//获得src文件的长度
	fseek(fp_src,0,SEEK_END);
	long len = ftell(fp_src);

	printf("len = %ld\n",len);
	
//	创建空洞文件
	fseek(fp_dest,len-1,SEEK_SET);
	fputc(0,fp_dest);
//	重置偏移
	rewind(fp_src);
	rewind(fp_dest);
//	开始拷贝
	char *p = malloc(len);
	fread(src,len,1,fp_src);
	fwrite(src,len,1,fp_dest);
//关闭文件	 
	fclose(fp_src);
	fclose(fp_dest);

/*
	char s[100]={0};
	while((fgetc(s,sizeof(s),fp_src))!=NULL)
	{
		fputc(s,fp_dest);
	}
	//实现copy功能
*/
	return 0;
}

总结:

1,标准IOh函数
2,文件操作:
	打开:fopen()
	读写:
		fgetc/fputc()
		fgets/fputs()
		fread/fwrite()
	定位:
		fseek()
		ftell()
		rewind()
	关闭:
		fclose()
其他函数:
	
	
feof() //判断流是结尾
ferror()//判断流是否出错
#include<stdio.h>
int main(int argc, const char *argv[])
{
	int ret;
	while((ret = fgetc(stdin))!=EOF)
	{
		fputc(ret,stdout);
	}
	printf("ret = %d\n",ret);

	if(feof(stdin))
	{
		printf("end of file\n");
	}else if(ferror(stdin)){
		printf("stdin error\n");
	}

	return 0;
}

系统调用文件IO:

不带缓存

操作对象:文件描述符(整数)

系统调用文件有哪些函数?

open()

close();

read();

write();

lseek();

int open(const char *pathname,int flags);
int open(const char *pathname,int flags,mode_t mode);

参数:
	@pathname
	@flags
		必选之一:
			O_RDONLY
			O_WRONLY
			O_RDWR
		可选项:
			O_APPEND 追加
			O_CREAT 不存在时创建
			O_TRUNC 截断长度为0的文件
组合:"a":O_WRONLY | O_APPEND	
	@mode
		只有在O_CREAT时,
		定义被创建文件的权限
返回值:
	成功:非负的整型数值
	失败:-1 & noerr

			

read:
	ssize_t read(int fd, void *buf,size_t count)
功能:从 文件描述符 中读取数据
参数:
	@fd 要读取的文件 对应的 文件描述符
	@buf 存放到内存的一块空间的地址
	@count 一次期望读取的最大字节数
返回值:
	成功: 返回成功读取了 字节数 0代表end of file
	失败: 返回 -1 & noerror
ps:会读取'\n'
	读取字符串需要添加'\0',否则有残留。
write:
	ssize_t write(int fd,const void*buff,size_ count);
功能:将数据 写到文件
参数:
	~
	~
	count:一次写操作 写入的字节数
返回值:
	成功:返回写入成功的字节数
	失败:-1 & noerr
read write open 实现cp功能:

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include<stdio.h>
int main(int argc, const char *argv[])
{
	if(argc!=3)
	{
		printf("err\n");
		return -1;
	}
	int fd_src = open(argv[1],O_RDONLY);
	int fd_dest = open (argv[2],O_WRONLY);
	if(fd_src<0||fd_dest<0)
	{
		perror("open fail\n");
		return -1;
	}
	char buf[100];
	int ret=0;
	while( ret = read(fd_src,buf,sizeof(buf)))
	{
		write(fd_dest,buf,ret);
	}
	close(fd_src);
	close(fd_dest);
	return 0;
}

标准IO中使用文件IO函数:

fileno:测试流指针,并转换流指针返回一个整型的文件描述符

int main()
{
	FILE* fp = FILE("1.txt","r");
	int fd = fileno(fd);
}

文件IO中使用标准IO函数:

fdopen:将文件描述符转换成流指针

int main()
{
	int fd=open("1.txt",O_RDONLY);//
	if(fd<0)
	{
		perror("open fail");
		return -1;
	}

	FILE *fp=fdopen(fd,"r");//这里打开方式权限需要小于等于之前open的打开权限,否则会报错
	if(fp=NULL)
	{
		perror("fopen fail");
		return -1;
	}
}

文件操作指目录文件:

opendir:打开一个流与目标目录对应,返回值是一个指针 DIR *,指向目录流,并定位在目录入口哦
		失败返回NULL
	
eg:opendir("/home/linux/res");

//使用opendir readdir 实现ls -i的功能:
int main ()
{
	DIR *dirp = opendir("123");//目录需要存在
	if(dirp == NULL)
	{
		perrpr("open fail");
		return -1;	
	}	

	struct dirent *pdir = NULL;
//	int i=0;
	while(pdir=readdir(dirp))
	{
		printf("ino:%d name:%s",pdir->d_ino,pdir->d_name);
	}
//	printf("")
}


struct dirent *readdir(DIR* dirp);
功能:
	从目录流中读取文件信息,并保存信息的结构体
参数:
	dirp:目录流指针
返回值:
	成功:包含文件信息的结构体
	失败:出错或者读到目录流末尾返回 NULL

栗子:统计目录中 常规文件 和 目录文件的个数:

#include<stdio.h>
#include <sys/types.h>
#include <dirent.h>

int main(int argc, const char *argv[])
{
	DIR *dp = opendir("/home/linux/shell/dir");	
	if(dp==NULL)
	{
		perror("open fail");
		return -1;	
	}	
	struct dirent *pdir = NULL;

	int cnt_REG=0;
	int cnt_DIR=0;
	while(pdir=readdir(dp))
	{
		if(pdir->d_type==DT_REG)
		{
			cnt_REG++;
		}else if(pdir->d_type==DT_DIR)
		{
			cnt_DIR++;
		}
	}
	closedir(dp);
	printf("REG:%d DIR:%d\n",cnt_REG,cnt_DIR);
	return 0;
}

linux@ubuntu:~/shell/dir$ l -l total 20 -rw-rw-r-- 1 linux linux 0 5月 29 14:08 1.txt -rw-rw-r-- 1 linux linux 0 5月 29 14:08 2.txt -rw-rw-r-- 1 linux linux 0 5月 29 14:08 3.txt -rwxrwxr-x 1 linux linux 8488 5月 29 14:25 a.out* -rw-rw-r-- 1 linux linux 472 5月 29 14:24 file_type.c drwxrwxr-x 2 linux linux 4096 5月 29 14:21 one/

说明drwxrwxr-x 2 linux linux 4096 5月 29 14:21 one/这列Linux代码中数字***2***的含义:

1,当文件是目录文件时,数字代表该目录下有几个子目录(包含.和…)

2,当文件是非目录文件时,数字代表该文件内容有几个 硬链接。

硬链接 :给文件取别名
	ln 源文件名 硬链接文件名
	与源文件直接关联。iNode号与源文件相同,修改一个,另一个同时被修改,但删除其中一个不会影响另一个文件,大小与源文件相同。
	特点:
		1,不占硬盘空间
		2,不能对目录进行操作
		3,不能跨文件系统
软链接 :相当于Windows中的快捷方式,用来记录我们目标的路径
	ln -s 源文件名 软链接名
	不与源文件关联,大小与源文件不同,一般为软链接自身文件大小。
	特点:
		1,占用磁盘空间
		2,可以对目录操作
		3,可以跨文件系统
创建硬链接和软链接:

硬链接:ln a.out hard_link
-rwxrwxr-x 2 linux linux 8488 529 14:25 a.out*
-rwxrwxr-x 2 linux linux 8488 529 14:25 hard_link*

软链接:ln -s a.out soft_link
-rwxrwxr-x 2 linux linux 8488 529 14:25 a.out*
lrwxrwxrwx 1 linux linux    5 529 14:55 soft_link -> a.out*
文件类型相关权限 目录 用户名 所在组 文件大小 最后被修改时间 文件名
stat函数:返回一个文件的信息
	int stat(const char *path,struct stat *buf);
功能:
参数:
	@const char *path 文件路径
	@struct stat *buf 
打印指定文件的iNode
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>

int main(int argc, const char *argv[])
{
/*
	DIR* dp = opendir("/home/linux/shell/dir");
	if(dp == NULL)
	{
		perror("open dir fail");
		return -1;
	}
*/
	struct stat statbuf;

	stat(argv[1],&statbuf);

	printf("inode = %ld\n",statbuf.st_ino);

	return 0;
}
实现目录拷贝
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>

//cp src dest 
int do_cp_file(const char *src, const char * dest)
{
	int fd_s = open(src,O_RDONLY);
	int fd_d = open(dest,O_WRONLY|O_CREAT|O_TRUNC,0666);

	if (fd_s < 0 || fd_d < 0)
	{
		perror("open fail");
		return -1;
	}

	off_t len = lseek(fd_s,0,SEEK_END);
	lseek(fd_d,len-1,SEEK_SET);
	write(fd_d,"",1);


	lseek(fd_s,0,SEEK_SET);
	lseek(fd_d,0,SEEK_SET);

	char buf[len];

	read(fd_s,buf,len);
	write(fd_d,buf,len);

	close(fd_s);
	close(fd_d);
	return 0;
}

int do_cp_dir(const char *dir1,const char *dir2) 
{
	//1.opendir 
	DIR *dir = opendir(dir1);

	if (dir == NULL)
	{
		perror("opendir fail");
		return -1;
	}


	struct dirent *pdir = NULL;
	
	while (pdir = readdir(dir))
	{
		// . ..
		//
		//src 
		// |--1.txt 
		// |--dir1 
		// |   |--2.txt 
		// |--3.c    
		if (strcmp(pdir->d_name,".")!=0&&strcmp(pdir->d_name,"..")!=0)
		{
			
           char spath[1024] = {0};
           char dpath[1024] = {0};

		   dir1[strlen(dir1)-1] == '/'?sprintf(spath,"%s%s",dir1,pdir->d_name):sprintf(spath,"%s/%s",dir1,pdir->d_name);
		   dir2[strlen(dir1)-1] == '/'?sprintf(dpath,"%s%s",dir2,pdir->d_name):sprintf(dpath,"%s/%s",dir2,pdir->d_name);

		   printf("src = %s\n",spath);
		   printf("dest = %s\n",dpath);
		   //mkdir  
		   if (pdir->d_type == DT_DIR)
		   {
			   mkdir(dpath,0777);
			   do_cp_dir(spath,dpath);
		   }else 
		   {
			   do_cp_file(spath,dpath);
			}
		}
	}

	return 0;
}

//./a.out d_src  d_dest
//./a.out src dest 
int main(int argc, const char *argv[])
{
	if (argc != 3)
	{
		printf("Usage: %s <dir1> <dir2>\n",argv[0]);
		return -1;
	}

	mkdir(argv[2],0777);
	do_cp_dir(argv[1],argv[2]);

	return 0;
}

小插曲:

chdir:改变当前工作目录
在C语言中,chdir函数用于更改当前工作目录。它的作用是将当前进程的工作目录更改为指定的目录。
chdir函数的原型为:
#include <unistd.h>
int chdir(const char *path);
参数path是要设置为新的当前工作目录的路径名。
如果调用成功,则返回0,否则返回-1并设置errno变量来指示出错的原因。常见的错误原因包括无法访问指定目录、路径名过长等等。


C语言中mkdir函数用于创建一个新的目录(文件夹)。

具体来说,该函数的作用是在指定的路径上创建一个包含指定权限的新目录。如果成功创建了目录,则返回0,否则返回-1并设置errno错误代码。

例如,下面的代码将在当前目录下创建名为“testdir”的新目录:
#include <sys/stat.h> 
#include <sys/types.h> 

int main() 
{ 
    char* dirname = "testdir"; 
    int status = mkdir(dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); 
    
    if (status != 0) { 
        // 处理失败情况
        return -1; 
    } 
    
    // 处理成功情况
    return 0; 
}
其中,第二个参数S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH表示为新目录指定了读取、写入和执行权限,这意味着用户、组和其他人都可以读取、写入和执行此目录。
getcwd() 是一个C标准库函数(stdlib.h 或 unistd.h 在头文件),通过调用该函数可以获取当前工作目录的路径名。 getcwd() 函数的原型如下所示:

c
#include <unistd.h>
char *getcwd(char *buf, size_t size);
buf:输出参数,代表了指向储存路径名称的内存地址。
size:缓冲区指针 buf 的大小。
在函数执行成功时,返回值指向包含当前工作目录字符串 (总长度不大于n) 的指针;如果失败,则返回 NULL,错误信息可由 errno 获取。

例如:

c
char buff[FILENAME_MAX];
getcwd(buff, FILENAME_MAX);
printf("Current working dir: %s\n", buff);
其中 buff 是自己定义的一个字符数组,FILENAME_MAX 是表示该数组空间的最大容量,即缓冲区的大小。
rmdir是C语言中的一个函数,用于删除指定目录。
rmdir用于删除空目录
具体来说,当调用 rmdir(dirname) 时,它会尝试删除给定名称的空目录。如果该目录包含子目录或文件,则该操作将失败并显示相应的错误信息。

以下是使用rmdir函数来删除目录的示例:

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

int main() {
    char dirname[] = "mydir";
  
    if (rmdir(dirname) == 0)
        printf("目录 %s 删除成功\n", dirname);
    else
        printf("目录 %s 删除失败\n", dirname);
    
    return 0;
}
在上面的示例中,我们首先定义了要删除的目录的名称(即“mydir”),然后通过调用rmdir函数来尝试删除该目录。如果删除成功,则输出“目录 mydir 删除成功”,否则输出“目录 mydir 删除失败”。

stat,fstat,lstat:

这三个函数的主要区别在于它们分别适用于哪种类型的文件描述符。

stat() 函数 适用于传入一个表示文件名的字符串参数。通过该函数可以获取了与文件相关的所有信息,包括文件大小、创建时间、修改时间等等。

fstat() 函数 适用于传入一个文件描述符参数(即已经打开的文件)。可用于在不知道文件名的情况下获取相应文件的所有信息。

lstat() 函数 与 stat() 类似,但是在遇到符号链接时会返回链接本身的所有信息,而不是被链接的目标文件所对应的信息。

access函数的第二个参数mode指定了检查文件是否存在、是否具有读权限、是否具有写权限等操作。它可以是以下几种值的按位或(“|”)操作:

  • F_OK:用于判断文件是否存在;
  • R_OK:用于判断文件是否可读;
  • W_OK:用于判断文件是否可写;
  • X_OK:用于判断文件是否可执行。

例如,如果我们想要判断文件是否存在且可读,则可以使用F_OK | R_OK作为mode参数传递给access函数。以下是一个示例代码:

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

int main(int argc, char *argv[]) {
    if (argc < 2) {
        fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
        return 1;
    }

    if (access(argv[1], F_OK | R_OK) == 0) {
        printf("File '%s' exists and is readable.\n", argv[1]);
        return 0;
    } else {
        printf("File '%s' does not exist or is not readable.\n", argv[1]);
        return 1;
    }
}

在上述代码中,我们将mode参数设置为F_OK | R_OK,表示要检查文件是否存在且可读。如果文件存在且可读,则返回0,否则返回-1并设置errno变量。

S_ISDIR的实现通常是使用位运算实现的。具体地说,它使用了一个叫作S_IFMT的宏,该宏定义了文件类型(file type)的掩码(mask)。S_IFMTmode进行按位与运算后,可以得到mode值中文件类型部分的值。然后,S_ISDIR将这个值与S_IFDIR比较,如果相等,则返回true,否则返回false

实现cp(复制文件)功能时,涉及到数据读写的操作。在选择将哪些函数用于实现cp功能时,需要考虑它们的效率和性能。下面对每个函数的效率进行简单分析。

  1. freadfwrite函数

freadfwrite函数是C标准库中用于二进制数据读写的函数。它们在处理大量数据时,比使用一次一个字符读取或写入数据要快得多,并且可以提高整个系统的效率。因此,在处理大量数据时使用它们的效率是非常高的。但是,它们无法处理包含二进制数据的文本文件,并且不支持Unicode编码。

  1. readwrite函数

readwrite函数是UNIX系统API中用于读写数据的函数。与freadfwrite函数类似,它们可以处理大量数据。如果需要处理大文件,则使用readwrite函数的效率更高。使用这些函数时,需要注意文件描述符的使用,因为它们是UNIX API的一部分,而不是C标准库的一部分。

  1. fgetsfputc函数

fgetsfputc函数是C标准库中用于文本文件读写的函数。它们可以处理包含文本数据的文件,并且支持Unicode编码。但是,因为它们需要依次读取或写入每个字符,因此在处理大量数据时会出现效率低的问题。

  1. fgetcputchar函数

fgetcputchar函数也是C标准库中用于文本文件读写的函数。虽然它们比fgetsfputc函数更高效,但是在读取或写入大量数据时仍然会存在性能问题。

综上所述,如果需要处理大量的二进制数据,则最好使用freadfwrite函数或readwrite函数;如果处理文本文件,则选择fgetsfputc函数可以保持代码可读性,但在性能方面表现较差,而fgetcputchar函数则更高效一些。需要根据具体情况进行选择。

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐