VS源文件提取工具vsjuicer 实现细节
程序的主体框架如下列代码所示:
//by btwsmile#include "stdafx.h"
#include "juice.h"// entry
int _tmain(int argc, _TCHAR* argv[])
{CJuice juicer(argc, argv);juicer.Process();return 0;
}
不难看出,真正进行处理的是CJuice类对象juicer。CJuice类定义在juice.h头文件中,它包含的成员变量有:
PTSTR m_pszWrongSyntax;
PTSTR m_pszInvalidPath;
PTSTR m_pszHelp;
int m_argc;
PTSTR* m_argv;
// complete delete
BOOL m_bComplete;
// report
DWORD m_dwFileCount;
DWORD m_dwFolderCount;
__int64 m_nFileSize;
DWORD m_dwMilliseconds;
// enum type
enum {VSJT_WRONGSYNTAX = 1,VSJT_INVALIDPATH,VSJT_QUERYHELP,VSJT_JUICE
};
前3个变量是字符串指针对象,它们是输出到屏幕上的提示信息。比如,当用户键入的命令有错误,则输出m_pszWrongSyntax提示语法错误。
m_argc和m_argv由main函数指定,它来自用户的输入。比如,用户键入命令vsj /help,此时m_argc = 2,而m_argv含两个字符串,即"vsj"和"/help"。
bool变量m_bComplete表示是否彻底删除文件和目录,缺省为FALSE,只有用户键入命令时使用了/C开关才将它置为TRUE。彻底删除的文件和目录不会进入回收站。
随后的4个整数变量是一些运行统计数据,依次表示:删除的文件计数、删除的目录计数、节省的磁盘空间以及操作所用的时间。
最后是一个匿名枚举,表示用户键入命令的意图。
CJuice类首先要实现自己的构造方法,在构造方法中初始化成员变量。
// constructor
CJuice(int argc, PTSTR* argv) : m_argc(argc), m_argv(argv), m_bComplete(FALSE),m_dwFileCount(0), m_dwFolderCount(0), m_nFileSize(0), m_dwMilliseconds(0)
{m_pszWrongSyntax = _T("Command syntax is incorrect.");m_pszInvalidPath = _T("Invalid directory path.");m_pszHelp = _T("\nVisual Studio Juicer (c)2012 by btwsmile")_T("\nDelete insignificant files and directories of visual studio solutions.")_T("\n\nVSJ path [/C]")_T("\n\npath\tDirctory path containing visual studio solutions.")_T("\n/C\tCompletely delete files and directories.")_T("\n\nThis command only delete")_T("\n(1) files with extension .sdf, .suo and .aps")_T("\n(2) directories named ipch, debug and release.");
}
为了代码美观一点,3个字符串指针对象的初始化并未放在初始化列表中,这样做也并不会损害程序的效率。
main函数构造了CJuice类对象后,立马调用了Process方法,因此,CJuice需向外提供Process方法。定义如下所示:
// process
void Process()
{int uRet = check_arguments();switch(uRet) {case VSJT_WRONGSYNTAX:display(m_pszWrongSyntax); break;case VSJT_INVALIDPATH:display(m_pszInvalidPath); break;case VSJT_QUERYHELP:display(m_pszHelp); break;case VSJT_JUICE:m_dwMilliseconds = ::GetTickCount();juice(m_argv[1]); m_dwMilliseconds = ::GetTickCount() - m_dwMilliseconds;report();};
}
首先调用了私有方法check_arguments,判断用户键入命令的意图,然后对不同情况进行响应。display方法的作用是打印传入的字符串参数,实现很简单:
// display message
void display(PTSTR psz)
{_tprintf(_T("%s\n"), psz);
}
juice是程序的核心方法,它将对目录进行提取处理,删除那些多余的中间文件。而report方法的作用是打印vsjuicer运行相关的统计数据。
下面依次来看check_arguments,juice以及report方法的实现。首先是check_arguments,其定义如下列代码所示:
// check arguments
UINT check_arguments()
{if(m_argc < 2 || m_argc > 3)return VSJT_WRONGSYNTAX;if(m_argc == 2) {if( ::lstrcmpi(m_argv[1], _T("/?")) == 0 ||::lstrcmpi(m_argv[1], _T("/help")) == 0)return VSJT_QUERYHELP;return is_path_valid() ? VSJT_JUICE : VSJT_INVALIDPATH;}if(::lstrcmpi(m_argv[2], _T("/c")) != 0)return VSJT_WRONGSYNTAX;else m_bComplete = TRUE;return is_path_valid() ? VSJT_JUICE : VSJT_INVALIDPATH;
}
对用户键入的命令进行检查,也就是检查命令参数是否正确。vsjuicer仅仅支持3条命令:
- vsj /?或vsj /help
- vsj path
- vsj path /c
因此m_argc只能是2或3,接着再分别对参数个数为2和3两种情况分别进行判断。check_arguments调用了私有方法is_path_valid,其作用是检查path是否有效,其定义为:
// is path valid
BOOL is_path_valid()
{if(!::PathFileExists(m_argv[1]))return FALSE;if(::PathIsDirectory(m_argv[1]) != FILE_ATTRIBUTE_DIRECTORY)return FALSE;return TRUE;
}
is_path_valid方法调用两个API函数来实现。
如果用户键入命令的意图是对path目录下的文件进行清理,check_arguments方法的返回值就是VSJT_JUICE。接着,juice方法就会被调用。前面已经说过,juice方法是程序最重要的部分,其实现相对复杂一些,我们先理一理思路:
- path目录下既包括普通文件,也包括子目录。
- 对普通文件来说,我们只需判断其后缀名是否为.sdf,.suo或.aps。如果是则删除之,否则就保留它。
- 对于子目录来说,首先要判断它的名字是否为ipch,debug或release。如果是则直接删除整个文件,否则就进入该目录,递归进行处理。
基于这样的思路,juice方法将是一个递归方法,传入参数pszPath是目录的全路径。juice方法的代码如下,稍微有一点复杂,随后我会对它进行说明。
// juice
void juice(PTSTR pszPath)
{ // delete folder if matchedPTSTR pszFolderName = folder_name(pszPath);if(pszFolderName) {if( ::lstrcmpi(pszFolderName, _T("ipch\\")) == 0 ||::lstrcmpi(pszFolderName, _T("debug\\")) == 0 ||::lstrcmpi(pszFolderName, _T("release\\")) == 0 ) {__int64 nSize = folder_size(pszPath);if(delete_item(pszPath)) {m_dwFolderCount++;m_nFileSize += nSize;}return;}}// delete files if matchedTCHAR szSubPath[MAX_PATH];TCHAR szFileName[MAX_PATH]; ::lstrcpy(szFileName, pszPath);::PathAddBackslash(szFileName);::lstrcat(szFileName, _T("*.*"));WIN32_FIND_DATA fd;BOOL bRet = TRUE;HANDLE hSearch = ::FindFirstFile(szFileName, &fd);while(hSearch != INVALID_HANDLE_VALUE && bRet) {// skip . and ..if(::lstrcmpi(fd.cFileName, _T(".")) == 0 ||::lstrcmpi(fd.cFileName, _T("..")) == 0) {bRet = ::FindNextFile(hSearch, &fd);continue;}// match and delete::memset(szSubPath, 0, sizeof(TCHAR)*MAX_PATH);::lstrcpy(szSubPath, pszPath);::PathAddBackslash(szSubPath);::lstrcat(szSubPath, fd.cFileName);if((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)juice(szSubPath);else {PTSTR pszExtension = ::PathFindExtension(szSubPath);if( ::lstrcmpi(pszExtension, _T(".sdf")) == 0 ||::lstrcmpi(pszExtension, _T(".suo")) == 0 ||::lstrcmpi(pszExtension, _T(".aps")) == 0 )if(delete_item(szSubPath)) {m_dwFileCount++;m_nFileSize += (fd.nFileSizeHigh * ((__int64)MAXDWORD+1)) + fd.nFileSizeLow;}}bRet = ::FindNextFile(hSearch, &fd);}// end while::FindClose(hSearch);
}
首先判断目录名称是否为ipch,debug或release,如果是则直接删除它,否则遍历该目录,分别处理各个文件和子目录。对于子目录的处理是递归调用juice方法来实现的。
juice方法调用了folder_name方法,它的作用是从目录全路径字符串中分解出目录的名称,本质是字符查找。其实现如下所示:
// folder name
PTSTR folder_name(PTSTR pszPath)
{::PathAddBackslash(pszPath);int nLen = ::lstrlen(pszPath);for(int i = nLen - 2; i > -1; --i)if(pszPath[i] == _T('\\') || pszPath[i] == _T('/'))return pszPath + i + 1;return NULL;
}
juice方法还调用了folder_size方法,它的作用是获取某个目录中所有文件的大小之和。因为没有直接的API方法获得目录的大小,所以需递归的遍历目录中的所有文件,将它们的大小累加起来。folder_size的方法如下所示:
// folder size
__int64 folder_size(PTSTR pszPath)
{__int64 nSize = 0;TCHAR szFileName[MAX_PATH];TCHAR szSubPath[MAX_PATH];BOOL bRet = TRUE;::lstrcpy(szFileName, pszPath);::PathAddBackslash(szFileName);::lstrcat(szFileName, _T("*.*"));WIN32_FIND_DATA fd;HANDLE hSearch = ::FindFirstFile(szFileName, &fd);while(hSearch != INVALID_HANDLE_VALUE && bRet) {// skip . and ..if(::lstrcmpi(fd.cFileName, _T(".")) == 0 ||::lstrcmpi(fd.cFileName, _T("..")) == 0) {bRet = ::FindNextFile(hSearch, &fd);continue;}// calculate sizeif((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)!= 0) {::memset(szSubPath, 0, MAX_PATH*sizeof(TCHAR));::lstrcpy(szSubPath, pszPath);::PathAddBackslash(szSubPath);::lstrcat(szSubPath, fd.cFileName);nSize += folder_size(szSubPath);}else nSize += fd.nFileSizeHigh*((__int64)MAXDWORD+1) + fd.nFileSizeLow;bRet = ::FindNextFile(hSearch, &fd);}::FindClose(hSearch);return nSize;
}
folder_size内部采用了与juice内部一样的遍历方法,即调用FindFirstFile,FindNextFile以及FindClose这3个API函数来实现。
对目录和文件的删除使用了统一的方式,都是调用的delete_item来实现的。delete_item方法的定义为:
// delete item
BOOL delete_item(PTSTR pszPath)
{TCHAR szTempPath[MAX_PATH] = { 0 };::lstrcpy(szTempPath, pszPath);FILEOP_FLAGS fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_ALLOWUNDO;if(m_bComplete) fFlags &= (~FOF_ALLOWUNDO);SHFILEOPSTRUCT fops = { NULL,FO_DELETE,szTempPath,NULL,fFlags,FALSE,NULL,NULL };int nRet = ::SHFileOperation(&fops);return nRet == 0 ? TRUE : FALSE;
}
其内部调用了API函数SHFileOperation。在填充SHFILEOPSTRUCT变量fops时,根据m_bComplete的值取舍FOF_ALLOWUNDO标志。
好了,就快大功告成了,还剩下最后一个方法report,它的定义再简单不过了:
// report
void report()
{_tprintf(_T("Juicing finished.")_T("\n\nTarget directory: %s")_T("\n\nDeleted\t %10d files.")_T("\nDeleted\t %10d directories.")_T("\n Saved\t %10.2lf kilobytes.")_T("\n Spent\t %10d milliseconds.\n"),m_argv[1], m_dwFileCount, m_dwFolderCount,(double)m_nFileSize/1024, m_dwMilliseconds);
}
4个整数变量的计算穿插在上述各个方法之中,比较简单,所以不在此处赘述。
这篇文件贴出了vsjuicer所用到的所有源码,读者完全可以将它们组织起来,顺利通过编译链接。如果你需要vsjuicer的solution files,请留言或发站内信索取。
VS源文件提取工具vsjuicer 实现细节相关推荐
- javadoc提取工具_使JavaDoc保持最新状态的工具
javadoc提取工具 在许多项目中,文档不是最新的. 更改代码后,很容易忘记更改文档. 原因是可以理解的. 在代码中进行更改,然后进行调试,然后希望在测试中进行更改(或者,如果您使用的是更多TDD, ...
- NLP标签/关键词-提取工具-java开发
一.简介 旨在帮助用户自动挖掘文本标签,是特征关键词提取工具,工具中集成了TextRank.TF-IDF算法.词跨度(SPAN)算法和LDA主题模型算法. 使用方法: 二.使用方法 2.1.TextR ...
- 小程序源码提取工具 完美解包,最新脚本,一键提取小程序源代码工具
小程序源码提取工具 完美解包,最新脚本,一键提取小程序源代码工具 小程序解包工具,具体功能请百度一下,解码后直接换掉人家的地址就OK 那么如何才能在手机里找到小程序的源文件包呢? 具体目录位置直接给出 ...
- CAB归档文件提取工具cabextract
CAB归档文件提取工具cabextract 在对Windows系统进行数字取证中,经常会遇到.cab的文件.该文件是Windows的压缩格式,一般是作为安装包文件.Kali Linux预置了专用的提取 ...
- Outlook数据提取工具readpst
Outlook数据提取工具readpst Outlook是Windows常用的邮件客户端.它将用户的信息保存到.pst文件中,如邮件.约会.日历.联系人等信息.为了便于查看这些信息,Kali Linu ...
- 信息批量提取工具bulk-extractor
信息批量提取工具bulk-extractor 在数字取证中,通常需要面对海量的数据,如几百GB甚至TB级别的数据.从这些海量数据中,提取有价值的数据是一个漫长.枯燥.繁琐的过程.Kali Linux提 ...
- 注册表数据提取工具RegRipper
注册表数据提取工具RegRipper 注册表是Windows操作系统一个数据库,用来存储系统和应用程序设置信息.注册表信息分别保存在操作系统中的6个Hive文件中.获取这几个文件,就可以从中提取注册表 ...
- 恶意软件 自动化规则提取工具 yargen 原理分析
yara是用来检测恶意软件的利器,yara规则由特征字符串.特征字节码等元素组成,只要恶意软件包含这些特征元素,就说明该文件是恶意的.但一个一个文件提特征是很耗人力的,所以业界就慢慢出现了一些出色的y ...
- Digital Color Meter 颜色值提取工具
本文已停止更新,点击此链接查看本文最新内容 !!! 1.Digital Color Meter 简介 Digital Color Meter 是一款 Mac 自带的颜色值提取工具. 其它下载地址 Di ...
最新文章
- IIS7.5 错误代码0x8007007e HTTP 错误 500.19
- Unexpected end of JSON input while parsing near
- 阿里中间件再获高度肯定,“三位一体”推动技术普惠
- c语言顺序查找算法,c语言实现排序和查找所有算法
- vue-cli2、vue-cli3脚手架详细讲解
- 为什么很多人C语言学不下去
- webpack4.0学习笔记
- 几台服务器怎么虚拟成一台,多台服务器虚拟成一台
- 最基本的25道深度学习面试问题和答案
- Java 全栈工程师进阶路线图
- 调和平均数,几何平均数,算数平均数,平方平均数
- 腾亚幕墙 HTML 教程
- H5开发html文件转换pdf,将HTML页面转换为PDF文件并导出
- 涨停前常见的K线形态
- html水晶按钮图片,css 如何实现一个水晶按钮的效果呢?
- 过完备深度子空间聚类网络:《Overcomplete Deep Subspace Clustering Networks》
- 无线破解攻击工具使用详解
- Qt+QtWebApp开发笔记(一):QtWebApp介绍、下载和搭建基础封装http轻量级服务器Demo
- java执行sql列名无效_JAVA 里查找SQL数据 列名无效
- LINUX FTP用户的创建