文件扩展名批量修改器

之前在使用SourceInsight查看一些开源项目的源代码时发现了一个很重要的问题,就是有些开源的工程的头文件现在都没有.h的后缀名了。编译器可以包含这些没有扩展名的头文件,但是使用SourceInsight打开这些工程时却没办法包含这些头文件,或者说即使包含了这些头文件在SourceInsight中查看源码时要找到某个类的声明更本找不到,不知道这算不算SourceInsight的一个bug。


我使用SouceInsight主要的原因就是开发时使用的开源库文档很少,很多时候要查看某个函数的用法都只能去查看源代码,然后在整个工程中查看这些函数是如何使用的。如果SourceInsight不能包含并且找到不带.h后缀的头文件,那基本就没有使用SourceInsight的必要了。


基于以上原因,做了一个对文件后缀名批量更改的工具,之前在网上也查找对文件进行批量更改的工具,功能很强大,但是用起来都不是很顺手,或者说不太符合我的要求吧,我只需要对符合条件的文件更改文件的后缀。


下面是软件的运行截图:



制作这个工具主要有两个问题:

  1. 类似于资源管理器这个界面的实现
  2. 文件名更改的规则如何制定
第一个问题其实可以使用一个简单的选择对话框指定路径来实现就可以,但是使用那种方法不能很直观地看到需要修改的文件,而且我要做的功能也不是很多,界面上完全有足够的空间来放置需要修改的目录和文件,所以选择了做一个资源管理器,这样看起来就方便多了。Visual Studio 2008 sp1就有实现这个资源管理功能的类了。分别是CMFCShellTreeCtrl和CMFCShellListCtrl,组合使用这两个类就可以实现出资源管理器的功能,特别要注意编译器需要时Visual Studio 2008 sp1,不能是Visual Studio 2008,后者没有这两个类。如果编译器是Visual Studio 2008,安装Visual Studio 2008 sp1的补丁就可以了,这个补丁可以在这里 下载

至于第二个问题才是关键,就是如何定义修改的规则,这个规则可以很简单也可以很复杂。因为我做这个工具的目的是修改头文件中不带后缀名的文件,所以直接使用了CString来操作。源文件名主要包括下面这些测试用例:
  1. *:匹配所有没有后缀名的文件(注意*这个通配符的含义本身是能匹配所有文件的)
  2. *.*:匹配带有后缀的文件,其中文件名可以是任意的,后缀也可以是任意的
  3. *.h:类似的这种表达式可以匹配所有后缀名是.h的文件
我主要更改了*这个通配符的含义,正常情况下它是能匹配所有文件的,这样我无法区分出那些不带后缀名的文件。

上图中“扩展文件名”一栏列出的就是修改后文件的扩展名了。

“递归遍历当前文件夹”如果选中可以一直递归遍历选中文件夹下面的文件,这个也很使用,如果只想更改当前文件夹下符合条件的文件那就不勾选,如果当前文件夹下的文件夹也需要进行修改,那就把这项勾上。

上面就是基本的说明,具体的代码实现如下:

1.首先使用Visual Studio 2008 sp1 建立一个基于对话框的MFC应用程序,如果使用的是sp1 ,那么那么建立的工程应该是继承CWinAppEx而不是继承自CWinApp,这点很关键,不然后面很多操作都执行不了。
2.在对话框中放置两个控件List Control 和Tree Control,然后在这两个控件上添加成员变量,分别命名为m_list和m_tree,然后在头文件CFileRenameDlg.h中修改它们的类型为CMFCShellListCtrl,CMFCShellTreeCtrl。设置List Control的属性,在面板里面设置View为Report 一定要设置这个,不然会出错,其余的属性可以设置Always Show为True,Alignment为Top;设置Tree Control的属性,Has Buttons 为True,Has Lines为True,Lines At Root为True
3.在CFileRenameApp::InitInstance()函数中添加下面一行代码InitShellManager();
4.最后在CFileRenameDlg::OnInitDialog()中添加将Tree Control和List Control关联到一起的代码:

	 m_tree.SetFlags((SHCONTF)(SHCONTF_FOLDERS));  //显示文件夹

	 m_tree.Expand(m_tree.GetRootItem(), TVE_EXPAND);
	 m_tree.SetRelatedList(&m_list);

基本上上面的操作完成后就可以看到资源管理器的界面了,此时已经解决了第一个问题,接下来就是解决第二个问题,获取文件名,并根据修改文件的规则来对文件进行修改。

此时主要涉及到CMFCShellListCtrl这个类的一些操作,包括获取到这个List Control的当前目录,以及CFileFind这个类,这个类可以用来遍历目录和文件。

在“批量命名”的响应函数中添加如下代码:
void CFileRenameDlg::OnBnClickedOk()
{
	UpdateData(TRUE);

	CString str;

	//获取是否进行递归的按钮
	isChecked =((CButton*)GetDlgItem(IDC_CHECK1))->GetCheck();

	int flag=AfxMessageBox("确定批量更改文件名?",MB_OKCANCEL);
	if (flag==IDCANCEL )
	{
		return;
	}

	//获取当前List的目录
	m_list.GetCurrentFolder(str);

	//文件重命名
	renameFiles(str);

	//刷新List Control的内容,这样修改完毕后就可以在界面上看到效果
	m_list.Refresh();

	
	//OnOK();
}

上面使用m_list.GetCurrentFolder(str);可以获取List Control的当前目录,然后将这个目录传递给renameFiles这个函数,这个函数会执行真正的重命名操作,并且根据界面上“递归遍历当前文件夹”这个选项是否选中来判断是否要对文件夹下面的文件夹进行递归遍历。

下面是最重要的函数renameFiles函数,根据上面的更改规则进行编写,如果上面的文件名修改规则改变了,这个函数也要改变。
bool CFileRenameDlg::renameFiles(CString  basePath)
{
	CFileFind finder;
	CString szPath=CString(basePath) + "\\"+m_sourcePath; 

	bool bPrefix=m_sourcePath.Find('.')==-1?false:true;//判断文件中是否指定'.',如果没有指定,表示要修改那么没有后缀名的文件

	CString desExt=m_desPath.Right(m_desPath.GetLength()-m_desPath.ReverseFind('.')-1);//获取.后缀
	bool bDes=m_desPath.Find('.')==-1?false:true;//判断修改后的文件中是否有后缀

	BOOL bFind=finder.FindFile(szPath);

	while(bFind)
	{
		bFind=finder.FindNextFile();
		//如果不是目录
		if (!(finder.IsDirectory()||finder.IsDots()))
		{
			//获取当前文件的文件名和后缀
			CString oldName,oldTitle;
			oldName=finder.GetFileName();
			oldTitle=finder.GetFileTitle();

			bool bOld=oldName.Find('.')==-1?false:true;//判断当前遍历的文件是否有后缀

			//1.如果源文件没有指定后缀并且当前遍历的文件也有没有后缀,那么进行更改
			//2.源文件有后缀名并且匹配
			if (!bPrefix&&!bOld||bPrefix)
			{
					try
					{
						//如果修改后的文件有后缀
						if(bDes)
							CFile::Rename(basePath+"\\"+oldName,basePath+"\\"+oldTitle+"."+desExt);
						else//如果修改后的文件没有后缀
							CFile::Rename(basePath+"\\"+oldName,basePath+"\\"+oldTitle);
					}
					catch (CFileException* e)
					{
					}
			}
		}

	}

	//递归遍历文件夹并修改文件夹内符合条件的文件
    szPath=CString(basePath) + "\\*.*"; 
	bFind=finder.FindFile(szPath);
	while(bFind)
	{
		bFind = finder.FindNextFile();
		if (finder.IsDirectory()&&!finder.IsDots()&&isChecked)//注意该句需要排除“.”“..”
		{
				renameFiles(basePath+"\\"+finder.GetFileTitle()+"\\");//注意这里不能是直接使用GetFileUrl函数
		}
	}

	finder.Close();
	return true;
}

整个工程的源代码下载: 下载页面
可执行程序的下载: 下载页面

下面是准备测试用的文件夹:

将没有后缀名的文件添加.txt后缀:

结果:



特别要注意,不要随便在任何目录下运行这个工具!!!


参考文章:

### 回答1: 可以使用 `rename` 命令来批量修改文件的后缀。 格式为:`rename 's/原后缀/新后缀/' *原后缀` 例如,将所有以 .txt 为后缀的文件后缀改为 .md,命令为: ``` rename 's/txt/md/' *txt ``` 注意, 这只是一种通用的做法,如果你的系统里没有rename命令,可能需要使用其他命令,比如find+mv。 ### 回答2: 要在Linux系统中批量修改文件后缀,可以使用shell脚本来完成。以下是一种可能的解决方案: 首先,打开终端并进入要修改文件后缀的目录。可以使用cd命令来导航到目标目录,例如: cd /path/to/directory 然后,创建一个新的shell脚本文件,例如rename.sh,并用本编辑器打开它: vi rename.sh 向该脚本文件中添加以下代码: #!/bin/bash for file in *; do if [ -f "$file" ]; then newname="${file%.*}.newext" mv "$file" "$newname" fi done 在这段代码中,“newext”是你想要的新文件后缀名,可以根据需要自行更改。然后保存并退出脚本文件。 接下来,给所创建的脚本文件添加可执行权限,使用以下命令: chmod +x rename.sh 最后,运行该脚本文件批量修改文件后缀,使用以下命令: ./rename.sh 脚本将会遍历目标目录中的所有文件,并将它们的后缀名替换为“newext”。确保在运行脚本之前备份目标目录中的文件,以防出现错误。 注意:本解决方案假设你已经安装了Bash shell。如果你使用的是其他shell相应地更改脚本文件的开头。 ### 回答3: 在Linux中,我们可以使用Shell脚本或者命令行工具来实现批量修改文件后缀。 1. 使用Shell脚本: 首先,创建一个新的Shell脚本文件,例如rename.sh。在脚本文件中,我们可以使用for循环来遍历所有的文件,并使用mv命令来修改文件的后缀。 以下是一个简单的示例代码: ```shell #!/bin/bash for file in *.txt; do mv "$file" "${file%.txt}.doc" done ``` 上述代码中,脚本会将所有的txt文件的后缀修改为doc。 保存并退出脚本文件,然后在终端中运行脚本文件: ```shell $ bash rename.sh ``` 这将完成文件后缀修改的批处理操作。 2. 使用命令行工具: 另一种方法是使用rename命令来批量修改文件后缀。rename命令可以通过正则表达式来匹配文件名,并将符合条件的文件重命名。 以下是一个使用rename命令的示例代码: ```shell $ rename 's/\.txt$/.doc/' *.txt ``` 上述命令将所有以txt结尾的文件的后缀修改为doc。 运行上述命令后,符合条件的文件的后缀将会被修改。 无论是使用Shell脚本还是命令行工具,都可以方便地实现Linux下的批量修改文件后缀操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值