Linux开发_文件目录操作介绍、创建BMP图片

240 阅读6分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第19天,点击查看活动详情

介绍Linux系统下两种文件编程接口,fopen.. (适合操作普通文件,C标准函数),open... (适合操作设备文件、也可以操作普通文件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文件

img

练习:

【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