1. 标准文件IO
1.1 知识点
2. fopen和fwrite、fread
2.1 使用fwrite和fread实现文件的拷贝
fcopy.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//使用fwrite和fread实现文件的拷贝
int main()
{
FILE *fp1 = fopen("./2.txt","r");
if(fp1 == NULL)
{
perror("open 1.txt failed");
return -1;
}
FILE *fp2 = fopen("./3.txt","w");
if(fp2 == NULL)
{
perror("open 1.txt failed");
return -1;
}
char *buf = calloc(5,20);
while(1)
{
int start = ftell(fp1);//获取偏移量
memset(buf,0,5*20);//清空
size_t n = fread(buf,20,5,fp1);//1.数据块读满了,n == 4,文件没读完, n==3//装不满一块数据块,数据块个数为0
if(n == -1)//结束
{
perror("fread failed");
return -1;
}
if(n == 5)//满了,文件不一定读完了
{
fwrite(buf,20,5,fp2);
}
if(n < 5)//结束
{
int end = ftell(fp1);
fwrite(buf,end-start,1,fp2);
fclose(fp1);
fclose(fp2);
break;
}
}
// while(fread(buf,1,1,fp1))
// {
// fwrite(buf,1,1,fp2);
// memset(buf,0,5*20);//清空
// }
// fclose(fp1);
// fclose(fp2);
return 0;
}
2. 目录和文件操作
2.1 知识点
现在来看看,对于一个目录而言,我们是怎么处理的。其实操作目录跟标准 IO 函数操 作文件类似,也是先获得“ 目录指针”,然后读取一个个的“目录项”。用到的接口函数是:
2.2 打开目录,查看普通文件
dir.c
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <dirent.h>
#include <stdio.h>
/*
struct dirent
{
ino_t d_ino; // 文件索引号
off_t d_off; // 目录项偏移量
unsigned short d_reclen; // 该目录项大小
unsigned char d_type; // 文件类型
char d_name[256]; // 文件名
};
*/
int main(int argc, char **argv)
{
DIR *dir = opendir(argv[1]);
struct dirent *ep;
while(1)
{
ep = readdir(dir);//每一个目录项都会获得一个指向目录项结构体的指针ep,直到ep为空
if(ep == NULL)
{
break;
}
if(ep->d_type == DT_REG)
{
printf("%s\n",ep->d_name);
}
}
closedir(dir);
}
2.3 递归删除目录
my_rm.c
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <dirent.h>
#include <stdio.h>
void myrm(char *path)//路径
{
DIR *dir = opendir(path);//获取目录指针
char pathname[128] = {0};//存放路径
struct dirent *ep;
while(1)
{
//读取目录
ep = readdir(dir);//每一个目录项都会获得一个指向目录项结构体的指针ep,直到ep为空
if(ep == NULL)
{
break;
}
//绕开两个隐藏的目录项.和.. ,用字符串比较函数strcmp(),和ep->name比较,如果相同,continue
if(strcmp(ep->d_name,".") == 0 || strcmp(ep->d_name,"..") == 0)
{
continue;
}
//普通文件
if(ep->d_type == DT_REG)
{
//argv[1]目录名称+文件名ep->d_name
//把ep->d_name和argv[1]贴到一个pathname
//举例
// /mnt/hgfs/qianrushi230901/read.c
snprintf(pathname,sizeof(pathname),"%s/%s",path,ep->d_name);
printf("贴好的文件路径:%s\n",pathname);
unlink(pathname);//删除文件
}
//目录
if(ep->d_type == DT_DIR)
{
//argv[1]目录名称+文件名ep->d_name
//把ep->d_name和argv[1]贴到一个pathname
//举例
// /mnt/hgfs/qianrushi230901/read
snprintf(pathname,sizeof(pathname),"%s/%s",path,ep->d_name);
printf("贴好的目录路径:%s\n",pathname);
myrm(pathname);//进入递归
}
rmdir(pathname);//删除目录
}
//关闭
closedir(dir);
}
int main(int argc, char **argv)
{
myrm(argv[1]);
}
3. 读取一行数据fgets
值得注意的有以下几点:
1 ,fgets( )跟 fgetc( )一样,当其返回 NULL 时并不能确定究竟是达到文件末尾还是碰 到错误,需要用 feof( )/ferror( )来进一步判断。
2,fgets( )每次读取至多不超过 size 个字节的一行,所谓“一行”即数据至多包含一个 换行符’\n’。
3,gets( )是一个已经过时的接口,因为他没有指定自定义缓冲区s 的大小,这样很容 易造成缓冲区溢出,导致程序段访问错误。
4,fgets( )和 fputs( ),gets( )和 puts( )一般成对使用,鉴于 gets( )的不安全性,一般 建议使用前者。