写点什么

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

作者:DS小龙哥
  • 2022 年 6 月 12 日
  • 本文字数:4599 字

    阅读完需:约 15 分钟

介绍 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 appprint.o:print.c  gcc print.c -cmain.o:main.c  gcc main.c -csum.o:sum.c  gcc sum.c -cclean:  rm app *.o -f
复制代码


发布于: 23 小时前阅读数: 4
用户头像

DS小龙哥

关注

之所以觉得累,是因为说的比做的多。 2022.01.06 加入

熟悉C/C++、51单片机、STM32、Linux应用开发、Linux驱动开发、音视频开发、QT开发. 目前已经完成的项目涉及音视频、物联网、智能家居、工业控制领域

评论

发布
暂无评论
Linux开发_文件目录操作介绍、创建BMP图片_6月月更_DS小龙哥_InfoQ写作社区