C++實現文件名批量修改
問題
用戶選擇需要修改文件後綴名的目錄,輸入後綴名後,對該目錄下的所有文件後綴名進行修改
實現
讀取目錄下的所有文件,同時修改文件後綴。在這個過程中,主要用到了幾個windows API:
- FindFirstFileA()
- FindNextFileA()
- FindClose()
以及C函數rename()
所用函數
HANDLE FindFirstFileA (LPCSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData);
- 含義:查找目錄下的第一個文件
- 參數:
lpFileName
:目錄名,如:”D:/Web/new/*” 或者 “D:\\Web\\new\\*” 用雙反斜槓是爲了防止目錄被轉義。同時要匹配目錄下的文件,最後應該使用通配符*,表示匹配目錄內文件 - 參數:
lpFindFileData
: 文件數據,這個一個定義好的數據結構,用於保存讀取到的文件的一些屬性。其中cFileName
表示文件名;具體定義如下
typedef struct _WIN32_FIND_DATAA {
DWORD dwFileAttributes;
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
FILETIME ftLastWriteTime;
DWORD nFileSizeHigh;
DWORD nFileSizeLow;
DWORD dwReserved0;
DWORD dwReserved1;
CHAR cFileName[MAX_PATH];
CHAR cAlternateFileName[14];
} WIN32_FIND_DATAA, *PWIN32_FIND_DATAA, *LPWIN32_FIND_DATAA; - 返回:返回一個文件句柄,用於之後的關閉或者查找下一個文件的操作
BOOL FindNextFileA (HANDLE hFindFile, LPWIN32_FIND_DATAA lpFindFileData);
- 含義:查找下一個文件
- 參數:
hFindFile
:文件句柄,由FindFirstFileA
返回獲得 - 參數:
lpFindFileData
: 文件數據,這個一個定義好的數據結構,用於保存讀取到的文件的一些屬性。其中cFileName
表示文件名 - 返回:布爾值,表示是否查找到下一個文件
BOOL FindClose (HANDLE hFindFile);
- 含義:關閉文件句柄
- 參數:
hFindFile
:文件句柄,由FindFirstFileA
返回獲得 - 返回:布爾值,表示關閉成功或失敗
int rename(const char *_OldFilename,const char *_NewFilename);
- 含義:將文件名OldFilename重命名爲NewFiename
- 參數:
*_OldFilename
:舊文件名 - 參數:
*_NewFilename
:新文件名 - 返回:修改成功返回0,失敗返回非0,可用
== 0
判斷是否修改成功
具體實現
在知道所用函數後,具體實現就比較簡單了,通過文件查找函數找到文件,再使用rename函數將文件重命名即可,在這個過程中,可以查找到一個文件就修改其後綴,也可以將文件全部查找遍歷完存入數組中來循環重命名
- 實現代碼
點擊獲取源碼
#ifndef FILEOPERATION_H
#define FILEOPERATION_H
#include <stdio.h>
#include <string>
#include <vector>
#include <windows.h>
class FileOperation
{
public:
FileOperation();
FileOperation(std::string dir, std::string suffix);
~FileOperation();
std::string err_msg() const { return err_msg_;}
int error_code() const { return error_code_;}
void set_error_code(int error_code) { error_code_ = error_code;}
void set_err_msg(std::string err_msg) { err_msg_ = err_msg;}
int Count() const { return file_list_->size();}
bool RenameFile();
protected:
void FindFiles();
private:
std::string dirname_;
std::string suffix_;
std::string err_msg_;
std::vector<std::string> *file_list_;
WIN32_FIND_DATAA current_file_;
HANDLE handle_;
int error_code_;
bool FindNext();
};
#endif // FILEOPERATION_H
- 具體實現
#include "FileOperation.h"
#include <algorithm>
#include <iterator>
#include <windows.h>
FileOperation::FileOperation() : dirname_("D:/web/new/"), suffix_("html"),
file_list_(new std::vector<std::string>()), error_code_(0)
{
}
FileOperation::FileOperation(std::string dir, std::string suffix) :
dirname_(dir), suffix_(suffix), file_list_(new std::vector<std::string>()), error_code_(0)
{
dirname_+= "/";
}
FileOperation::~FileOperation()
{
delete file_list_;
}
bool FileOperation::RenameFile()
{
this->FindFiles();
for(std::string &file_data : *file_list_) {
//從尾部開始找‘.’,中間的.不修改
// auto name_iter = std::find(file_data.cbegin(), file_data.cend(), '.');
auto name_iter = std::find(file_data.crbegin(), file_data.crend(), '.');
std::string name = std::string(file_data.cbegin(), name_iter.base());
name += suffix_;
name = dirname_ + name;
if ( rename((dirname_ + file_data).c_str(), name.c_str()) != 0) {
error_code_ = -1;
err_msg_ += "文件"+ file_data +"更改失敗";
}
}
return true;
}
void FileOperation::FindFiles()
{
LPCSTR dirname = (dirname_ + "*").c_str();
handle_ = ::FindFirstFileA(dirname, ¤t_file_);
if (handle_ != INVALID_HANDLE_VALUE) {
if (FindNext())
while (FindNext()) {
file_list_->push_back(current_file_.cFileName); //從第三個文件開始,前兩個不寫入
}
}
::FindClose(handle_);
}
bool FileOperation::FindNext()
{
return ::FindNextFileA(handle_, ¤t_file_);
}
需要注意的是:在windows目錄下,讀取出來的文件中,前兩個文件分別爲/.,/ ..,因此,爲了避免這種情況,在讀取到第三個文件時開始往vector裏寫入數據