一.序
前面两篇文章对注释转换以及目录级联转换的算法思想以及实现思路进行了阐述,接下来进行正式实现
二.实现思路图解

三.具体实现
1.convert.cpp
根据用户选项,调用正确的函数

//convert.cpp
#include"ConvertComment.h"
#include"BrowseDir.h"

int main(int argc, char *argv[])
{
//操作选择
int opt = -1;
while((opt = getopt(argc, argv, "s::S::r::R::h::H::")) != -1) //::代表后面可跟字母或者也可不跟
{
switch(opt)
{
case 'S':
case 's':
SeeArgc(argc);
OneFileCovert(argv[3], argv[2]);
break;
case 'R':
case 'r':
SeeArgc(argc);
DirConvert(argv[3], argv[2]);
break;
case 'H':
case 'h':
help();
break;
default:
cout<<"Usage: ./convert [-Option] src dest"<<endl;
cout<<"[Option]: S/R/H"<<endl;
break;
}
}
SeeArgc(argc);
return 0;
}

2.BrowseDir.h
DirConvert,OneFileConvert,及需要的对目录操作函数的实现

//BrowseDir.h
#ifndef _BROWSEDIR_H
#define _BROWSEDIR_H

#include"utili.h"
#include"ConvertComment.h"

void FileCp(char *des, char *src); //复制文件
BOOL IsCFile(char *file); //判断是否是.c文件
BOOL IsCppFile(char *file); //判断是否是.cpp文件
char* GetFileName(char *NamePath); //只获取文件名or目录名
void PathCat(char *desPath, char *srcPath); //目录后追加文件名或者路径
int PathCmp(char *dir1, char *dir2); //(注释转换没用到)比较两个目录是否同级(深度相同)1 0 -1
int PathDep(char *dir); //(注释转换没用到)统计目录的深度
void help(); //帮助文档
void SeeArgc(const int count); //判断参数数量是否正确
void OneFileCovert(char *des, char *src); //单个文件的注释转换
void DirConvert(char *des, char *src); //目录的递归转换
void BeginConvert(char *des, char *src); //进行目录递归转换
size_t GetFileSize(FILE *NamePath); //获取一个文件的大小

size_t GetFileSize(FILE *NamePath)
{
size_t size = 0;
fseek(NamePath, 0, SEEK_END);
size = ftell(NamePath);
cout<<"大小为:"<<size<<endl;
return size;
}
void FileCp(char *des, char *src)
{
FILE *inputfile = fopen(src, "rb");
if(NULL == inputfile)
{
cout<<"Open src file Fail!"<<endl;
exit(EXIT_FAILURE);
}
size_t SIZE = GetFileSize(inputfile);
fseek(inputfile, 0, SEEK_SET); //使文件流指针回到文件开始
char buf[SIZE+1];

FILE *outputfile = fopen(des, "wb");
if(NULL == outputfile)
{
cout<<"Open des file Fail!"<<endl;
exit(EXIT_FAILURE);
}
while(!feof(inputfile))
{
fread(buf, sizeof(char), SIZE, inputfile);
fwrite(buf, sizeof(char), SIZE, outputfile);
}
fclose(inputfile);
fclose(outputfile);
}
BOOL IsCFile(char *file)
{
int len = strlen(file);
if(file[len-1] == 'c' && file[len-2] == '.')
return TRUE;
else
return FALSE;
}
BOOL IsCppFile(char *file)
{
int len = strlen(file);
if(file[len-1] == 'p' && file[len-2] == 'p'
&& file[len-3] == 'c' && file[len-4] == '.')
return TRUE;
else
return FALSE;
}
char* GetFileName(char *NamePath)
{
if(NULL == NamePath)
{
cout<<"NamePath is NULL!"<<endl;
exit(EXIT_FAILURE);
}
int len = strlen(NamePath);
char *Current = NULL;
while(len > 0 && NamePath[len] != '/')
{
len--;
}
if(NamePath[len] == '/')
Current = &NamePath[len] + 1;
else
Current = &NamePath[len];
return Current;
}
void PathCat(char *desPath, char *srcPath)
{
char *ptrdes;
char *srcPathname = GetFileName(srcPath);
if(lstat(desPath, &statbuf) < 0)
{
cout<<"lstat error!"<<endl;
exit(EXIT_FAILURE);
}
if(desPath[strlen(desPath)] != '/' && S_ISDIR(statbuf.st_mode) != 0)
{
ptrdes = desPath + strlen(desPath);
*ptrdes++ = '/';
*ptrdes = 0;
}
strcat(desPath, srcPathname);
}
int PathDep(char *dir)
{
int len = strlen(dir);
int count = 0;
while(len-- > 0)
{
if(dir[len] == '/')
++count;
}
return count;
}
int PathCmp(char *dir1, char *dir2)
{
if(PathDep(dir1) > PathDep(dir2))
return 1;
else if(PathDep(dir1) == PathDep(dir2))
return 0;
else
return -1;
}

void OneFileCovert(char *des, char *src)
{
FILE *inputfile = fopen(src, "r");
if(NULL == inputfile)
{
cout<<"Open src file Fail!"<<endl;
exit(EXIT_FAILURE);
}
FILE *outputfile = fopen(des, "w");
if(NULL == outputfile)
{
cout<<"Open des file Fail!"<<endl;
exit(EXIT_FAILURE);
}

ConvertComment(inputfile, outputfile);

fclose(inputfile);
fclose(outputfile);
}
void DirConvert(char *des, char *src)
{
char src_path[_POSIX_PATH_MAX];
memset(src_path, 0, _POSIX_PATH_MAX);

struct dirent *dirp;
DIR *dpsrc; //源目录
DIR *dpdes; //目的目录
if(NULL == des || NULL == src) //参数检测
{
cout<<"des/src is NULL!"<<endl;
exit(EXIT_FAILURE);
}
if(NULL == (dpdes = opendir(des))) //如果目的目录不存在,则创建
{
mkdir(des, 0755);
}
if(NULL == (dpsrc = opendir(src))) //如果源目录不存在,退出程序
{
perror("opendir src");
exit(EXIT_FAILURE);
}
if(NULL == realpath(src,src_path)) //src给src_path
{
perror("realpath src");
exit(EXIT_FAILURE);
}
//readdir读取src的顺序为:t1,t2,t3,input.c
while((dirp = readdir(dpsrc)) != NULL)
{
if(strcmp(dirp->d_name, ".") == 0 ||
strcmp(dirp->d_name, "..") == 0)
continue; //忽略"."和".."
PathCat(src_path,dirp->d_name);
cout<<src_path<<endl;
BeginConvert(des,src_path); //des=./t1 src_path=./tttttt/t1
if(NULL == realpath(src,src_path))//将src_path恢复成src
{
perror("realpath src");
exit(EXIT_FAILURE);
}
}
closedir(dpsrc);
closedir(dpdes);
}
void BeginConvert(char *des, char *src) //des=./t1 src=./tttttt/t1
{
//(1)将src,des的路径转化成绝对路径分别存于src_path,des_path中
//(2)获取src的属性。
//(3)分情况讨论
//a.如果src是文件,判断是否是.c/.cpp文件,des_path追加这一文件,然后直接调动OneFileConvert()进行转换
//b.如果src是目录,des_path追加这一目录,然后DirpConvert(des_path,src_path)

//(1)
char *srcfilename = GetFileName(src);
char src_path[_POSIX_PATH_MAX];
memset(src_path, 0, _POSIX_PATH_MAX);
char des_path[_POSIX_PATH_MAX];
memset(des_path, 0, _POSIX_PATH_MAX);
if(NULL == realpath(src, src_path))
{
perror("realpath src");
exit(EXIT_FAILURE);
}
if(NULL == realpath(des, des_path))
{
perror("realpath des");
exit(EXIT_FAILURE);
}
//(2)
if(lstat(src_path, &statbuf) < 0)
{
perror("lstat src");
exit(EXIT_FAILURE);
}
//(3)
//a.文件
if(S_ISDIR(statbuf.st_mode) == 0)
{
if(IsCFile(src_path) || IsCppFile(src_path))
{
PathCat(des_path, srcfilename);
OneFileCovert(des_path, src_path);
}
else //只是单纯的写拷贝文件
{
PathCat(des_path, srcfilename);
FileCp(des_path, src_path);
}
}
//b.目录
else
{
PathCat(des_path, srcfilename);
DirConvert(des_path, src_path);
}
}
void help()
{
FILE *README = fopen("README.md", "r");
if(NULL == README)
{
cout<<"Open README.md fail!"<<endl;
exit(EXIT_FAILURE);
}
char buf[READMESIZE];
while(!feof(README))
{
fgets(buf, READMESIZE, README);
cout<<buf<<endl;
}
}
void SeeArgc(const int count)
{
if(count != 4)
{
cout<<"Argument is error!"<<endl;
exit(EXIT_FAILURE);
}
}

#endif

四.收获
1.学会了gdb的带参调试
2.会使用目录操作函数及文件操作函数实现自己的小想法,这次目录级联转换的小项目主要使用到了这些函数:
lstat获取文件属性,opendir–>readdir–>closedir的目录操作流程,realpath将相对路径转化成绝对路径。
3.注意到的问题:

dirp = readdir(dirname);
如果将dirp->d_name转化成绝对路径,只是给dirp->d_name字符串前面添加了源程序(即代码执行路径),而不是真正的绝对路径,这样会导致,下一次递归打开dirp->d_name时,程序报错,文件不存在!所以我的程序中加入了将dirp->d_name与其所在目录绝对路径的字符串拼接函数PathCat,当然这给与其无关的某些操作也提供了方便。

源码请戳
https://github.com/zhangzhuo233/little_project/tree/master/ConvertComment/day2

更多相关文章

  1. CentOS7.2 通过nfs设置共享文件夹
  2. linux下查找包含关键字的文件
  3. Linux系统下Tar文件安装方法
  4. Linux学习笔记(九)--RedHat 7.0之用户身份与文件权限、存储结构与
  5. 在Linux用tar归档压缩文件时忽略某些文件和目录
  6. 如何查找特定用户可执行的所有文件(不是最新的)
  7. 使用/proc/meminfo文件查看内存状态信息
  8. linux下socket通信常用的结构与头文件
  9. ldconfig报错 :libstdc++.so.6.0.18-gdb.py不是一个elf文件

随机推荐

  1. 6道tomcat面试题,最后两道难倒我了
  2. ESXi GPU 直通
  3. RPA:如何给财务人员带来新机遇?
  4. 快速上手最新的 Vue CLI 3[每日前端夜话0
  5. 浏览器中的JavaScript:文档对象模型与 DOM
  6. Android(安卓)init源代码分析(1)概要分析
  7. Git 分支简介、Git 和 GitHub 日常操作[
  8. centos7下自动编译升级openssh和OpenSSL
  9. JavaScript 闭包基本指南 [每日前端夜话0
  10. Android(安卓)bionic缺失pthread_cancel