介绍 Linux 系统下两种文件编程接口,fopen、fclose、fread、fwrite (适合操作普通文件,C 标准函数),open、close、read、write (适合操作设备文件、也可以操作普通文件 Linux 下接口),介绍目录相关操作函数,Makefile 文件等等。
任务 1: 文件操作函数学习
学习两套函数:
(1) C 语言下标准文件操作函数。fopen、fclose、fread、fwrite (适合操作普通文件)
针对文件指针操作。
(2) Linux 下专用的文件操作函数。open、close、read、write (适合操作设备文件、也可以操作普通文件)
针对文件描述符操作。
如何检测文件是否读取到结尾? 判断读函数的返回值。
文件操作相关的练习
【1】 (编码)创建一张 BMP 图片,颜色可以指定。
【2】模拟 du 命令,可以查看指定文件的大小,可以将文件大小打印出来。
【3】文件加密和解密。 密码: 数字方式、字符串方式
加密方式: 异或加密
扩展: 加密方式: MD5 加密
扩展作业: 实现文件的压缩和解压,模拟 tar 命令。
创建 BMP 图片:
#include <stdio.h>
#include <string.h>
/* 必须在结构体定义之前使用,这是为了让结构体中各成员按1字节对齐 */
#pragma pack(1)
/*需要文件信息头:14个字节 */
struct tagBITMAP_FILE_HEADER
{
unsigned short bfType; //保存图片类似。 'BM' -- 0x4d42
unsigned int bfSize; //图片的大小
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned int bfOffBits; //RGB数据偏移地址
};
/* 位图参数信息 */
struct tagBITMAP_INFO_HEADER {
unsigned long biSize; //结构体大小
unsigned long biWidth; //宽度
unsigned long biHeight; //高度
unsigned short biPlanes;
unsigned short biBitCount; //颜色位数
unsigned long biCompression;
unsigned long biSizeImage;
unsigned long biXPelsPerMeter;
unsigned long biYPelsPerMeter;
unsigned long biClrUsed;
unsigned long biClrImportant;
};
/*
函数功能: 创建一张BMP图片
函数参数:
char *name 文件名称
int w 宽度
int h 高度
int c 颜色位数
函数返回值: 0表示成功
*/
int CreateBmpImage(char *name,int w,int h,int c)
{
/*1. 创建文件*/
FILE *file=fopen(name,"wb");
if(file==NULL)return 1;
/*2. 创建BMP文件头*/
struct tagBITMAP_FILE_HEADER head;
memset(&head,0,sizeof(struct tagBITMAP_FILE_HEADER));
head.bfType=0x4d42; //BMP图片的类型
head.bfSize=sizeof(struct tagBITMAP_FILE_HEADER)+sizeof(struct tagBITMAP_INFO_HEADER)+w*h*3;
head.bfOffBits=sizeof(struct tagBITMAP_FILE_HEADER)+sizeof(struct tagBITMAP_INFO_HEADER);
if(fwrite(&head,1,sizeof(struct tagBITMAP_FILE_HEADER),file)!=sizeof(struct tagBITMAP_FILE_HEADER))
{
return 2;
}
/*3. 创建BMP图像参数信息*/
struct tagBITMAP_INFO_HEADER info;
memset(&info,0,sizeof(struct tagBITMAP_INFO_HEADER));
info.biSize=sizeof(struct tagBITMAP_INFO_HEADER);
info.biWidth=w;
info.biHeight=h;
info.biBitCount=24;
info.biPlanes=1;
if(fwrite(&info,1,sizeof(struct tagBITMAP_INFO_HEADER),file)!=sizeof(struct tagBITMAP_INFO_HEADER))
{
return 3;
}
/*4. 图片颜色数据填充*/
int i,j;
for(i=0;i<h;i++)
{
for(j=0;j<w;j++)
{
if(fwrite(&c,1,3,file)!=3)
{
return 4;
}
}
}
/*5. 关闭文件*/
fclose(file);
}
//argc :表示参数的数量
//argv :二维指针,指向传入的每一个字符串首地址
int main(int argc,char **argv)
{
if(argc!=2)
{
printf("参数格式:./app <图片的名称>\n");
return 0;
}
if(CreateBmpImage(argv[1],320,480,0xFF0033))
{
printf("图片创建失败!\n");
}
else
{
printf("图片创建成功!\n");
}
return 0;
}
复制代码
BMP 图片练习文件操作(专题练习):
【1】BMP 图片数据取模,模拟图片取模软件。(选择 16 位或者 24 位取模方式)
【2】BMP 图片放大缩小,根据输入的尺寸放大缩小图片。
【3】实现图片 4 种翻转效果: 上、下、左、右。
文件系统:
【1】文件系统本身就是一套上层(软件层)算法,底层有与硬件交互的接口。
硬件: 磁盘、U 盘、SD 卡 (扇区)…….
【2】文件本身属于一个容器,没有规定存放什么类型的数据。
【3】文件指针(光标位置),会随着读写函数移动。
【4】文件读写权限: 打开文件需要选择正确的权限。
文件格式介绍:
图片: BMP、PNG、JPG/JPEG、GIF、ICO
音频/视频: MP3、MP4
文本: txt(字符串)
文档: doc
Main 函数传递参数
#include <stdio.h>
int main(int argc,char **argv)
{
//argc :表示参数的数量
//argv :二维指针,指向传入的每一个字符串首地址
int i;
for(i=0;i<argc;i++)
{
printf("argv[%d]=%s\n",i,argv[i]);
}
return 0;
}
复制代码
目录过滤:
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include <stdlib.h>
#include <string.h>
// ./app <dir_path> <.mp3>
/*
函数功能: 输出指定目录下指定指定后缀的文件名称+路径
./app /bmp/jpg/ .mp3
*/
int PrintDirName(char *DirName,char *str)
{
/*1. 打开目录*/
DIR *dirp=opendir(DirName);
if(dirp==NULL)return 1;
/*2. 循环读取目录*/
struct dirent *file_p=NULL;
char *findstr=NULL;
char *addr_p=NULL; //存放最终完整的文件名称
while(file_p=readdir(dirp))
{
char *findstr=strstr(file_p->d_name,str);
if(findstr)//123.mp3 123.mp3.mp4 123.mp3.txt
{
//比较后缀
if(strcmp(findstr,str)==0)
{
addr_p=malloc(strlen(DirName)+strlen(file_p->d_name)+1);
strcpy(addr_p,DirName); //拼接目录
strcat(addr_p,file_p->d_name);//拼接文件名称
printf("文件完整路径=%s\n",addr_p);
free(addr_p); //释放空间
}
}
}
/*3. 关闭目录*/
closedir(dirp);
return 0;
}
int main(int argc,char **argv)
{
if(argc!=3)
{
printf("./app <dir_path> <.mp3>\n");
return 0;
}
PrintDirName(argv[1],argv[2]);
return 0;
}
复制代码
任务 2: 目录相关操作函数
创建目录、打开目录、读取目录。
需求: 获取指定目录下指定后缀的所有文件,并且输出每个文件的路径信息。
练习: 拷贝目录下所有文件(指定后缀的文件)到指定目录下,考虑一层目录。
扩展: 递归拷贝,考虑多层目录。
单层目录拷贝:
#ifndef CPCMD_H
#define CPCMD_H
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
int CopyFile(char *src_file,char *new_file);
int CopyDir(unsigned char *src_dir,unsigned char *new_dir);
#endif
#include "CpCmd.h"
/*
参数说明:./a.out <源目录或者文件> <目标目录或者文件>
./aout 123.c /work/456.c
./a.out 123.c 456.c
./a.out /work/ /123/
*/
int main(int argc,char *argv[])
{
/*1. 判断参数是否正确*/
if(argc!=3)
{
printf("./a.out <源目录或者文件> <目标目录或者文件>\n");
return 0;
}
/*2. 获取文件的状态信息*/
struct stat stat_buf;
if(stat(argv[1],&stat_buf)!=0)
{
printf("拷贝的源文件不存在!\n");
exit(-1);
}
/*3. 区分拷贝目录还是拷贝文件*/
if(S_ISREG(stat_buf.st_mode))
{
/*拷贝文件*/
if(CopyFile(argv[1],argv[2])==0)
{
printf("文件拷贝成功!\n");
}
else
{
printf("文件拷贝失败!\n");
}
}
else if(S_ISDIR(stat_buf.st_mode))
{
/*拷贝目录*/
if(CopyDir(argv[1],argv[2])!=0)
{
printf("目录拷贝失败!\n");
}
}
else
{
printf("参数错误,拷贝无法执行!\n");
}
return 0;
}
/*
函数功能:拷贝文件
函数参数:
char *src_file:源文件的名称与路径
char *new_file:目标文件的名称与路径
*/
int CopyFile(char *src_file,char *new_file)
{
/*1. 打开源文件、创建新文件*/
FILE*srcfile=fopen(src_file,"rb");
FILE*newfile=fopen(new_file,"wb");
if(srcfile==NULL)
{
printf("行号:%d_文件打开失败!\n",__LINE__);
return -1;
}
if(newfile==NULL)
{
printf("行号:%d_文件创建失败!\n",__LINE__);
return -1;
}
/*2. 拷贝文件*/
char buff[100];
int cnt;
while(!feof(srcfile))
{
cnt=fread(buff,1,100,srcfile); //读取数据
fwrite(buff,1,cnt,newfile);
}
/*3. 关闭文件*/
fclose(srcfile);
fclose(newfile);
return 0;
}
/*
函数功能: 拷贝目录
函数参数:
unsigned char *src_dir:源目录
unsigned char *new_dir:目标目录
返回值:
0表示成功
负数表示失败
*/
int CopyDir(unsigned char *src_dir,unsigned char *new_dir)
{
/*1. 打开目录*/
DIR *SrcDir=opendir(src_dir);
if(SrcDir==NULL)
{
printf("拷贝的源目录不存在!\n");
return -1;
}
DIR *NewDir=opendir(new_dir);
if(NewDir==NULL)
{
if(mkdir(new_dir,0777)<0)
{
printf("目录创建失败!\n");
return -1;
}
}
/*循环遍历目录*/
struct dirent *dirinfo;
while(dirinfo=readdir(SrcDir))
{
struct stat stat_buf;
int src_len=0;
char *src_p;
src_len=strlen(src_dir); //得到源目录字符串长度
src_len+=strlen(dirinfo->d_name); //得到文件名称的字符串长度
src_p=malloc(src_len); //申请存放源目录路径的空间
strcpy(src_p,src_dir);
strcat(src_p,dirinfo->d_name);
if(stat(src_p,&stat_buf)==0)
{
/*3. 区分拷贝目录还是拷贝文件*/
if(S_ISREG(stat_buf.st_mode))
{
int new_len=0;
char *new_p;
new_len=strlen(new_dir); //得到源目录字符串长度
new_len+=strlen(dirinfo->d_name); //得到文件名称的字符串长度
new_p=malloc(src_len); //申请存放源目录路径的空间
strcpy(new_p,new_dir);
strcat(new_p,dirinfo->d_name);
/*拷贝文件*/
if(CopyFile(src_p,new_p)!=0)
{
printf("src_p=%s\n",src_p);
printf("new_p=%s\n",new_p);
printf("文件拷贝失败!\n");
}
free(new_p); //释放空间
}
}
else
{
return -1;
}
free(src_p); //释放空间
}
return 0;
}
复制代码
任务 3: Makefile 文件
练习:
【1】使用 Makefile 建立工程,只需要写一个 Makefile 文件。
【2】使用 Makefile 建立工程,每个目录下就写一个 Makefile 文件。
app:print.o main.o sum.o
gcc main.o print.o sum.o -o app
print.o:print.c
gcc print.c -c
main.o:main.c
gcc main.c -c
sum.o:sum.c
gcc sum.c -c
clean:
rm app *.o -f
复制代码
评论