1. 程式人生 > 實用技巧 >【轉載】Linux C++ 實現檔案目錄常見操作(拷貝檔案,拷貝目錄,獲取檔案大小,獲取目錄大小,獲取目錄下所有檔名,...)

【轉載】Linux C++ 實現檔案目錄常見操作(拷貝檔案,拷貝目錄,獲取檔案大小,獲取目錄大小,獲取目錄下所有檔名,...)

原文:https://www.cnblogs.com/sinicheveen/p/13680327.html

1. 環境

  • Linux(Ubuntu)
  • C++11
  • gcc 7.5.0
  • g++ 7.5.0
  • 這些常用操作封裝為了一個 C++ 類FileOperation
  • 對檔案的操作基本都是使用的 C 函式,沒有用 C++ 的fstream相關類
  • 針對 Linux 系統寫的,涉及到 Linux 專有函式,因此對 Windows 系統可能不適用

2. 程式碼

FileOperation.h

#pragma once

/*
*Environment:
*Linux(Ubuntu), C++11,gcc 7.5.0,g++ 7.5.0
*Description:
*檔案和目錄操作(e.g. 拷貝檔案,拷貝目錄,計算目錄大小,...)
*/

#ifndef PARAMETER_FLOW
#define PARAMETER_FLOW
#define IN
#define OUT
#define INOUT
#endif    //PARAMETER_FLOW

#ifndef BASE_TYPE_DEF
#define BASE_TYPE_DEF
#include <stdint.h>
typedef int16_t          SHORT;
typedef uint16_t         USHORT;
typedef int32_t          INT;
typedef uint32_t         UINT;
typedef int64_t          DLONG;
typedef uint64_t         DULONG;
typedef void             VOID;
typedef bool             BOOL;
typedef signed char      CHAR;
typedef signed char      BYTE;
typedef unsigned char    UCHAR;
typedef float            FLOAT;
typedef double           DOUBLE;
#endif    //BASE_TYPE_DEF

#include <dirent.h>
#include <string>
#include <string.h>
#include <sys/stat.h>
#include <type_traits>
#include <unistd.h>
#include <utility>
#include <vector>
#include <sys/vfs.h>

using std::make_pair;
using std::pair;
using std::string;
using std::vector;

/*
Explain:
 - fileLongName:加了路徑的檔名,e.g. /root/xxx/1.txt
 - fileShortName:沒有加路徑的檔名,e.g. 1.txt
 - dirLongName:加了路徑的目錄名,e.g. /root/xxx/MyDocuments
 - dirShortName:沒有加路徑的目錄名,e.g. MyDocuments
*/

class FileOperation
{
public:
    /*
    *Function    : getDirSize
    *Description : 獲取目錄大小
    *Modify      : 2020.09.16
    *Input       : IN const string& dirLongName,目錄名
    *            : OUT DLONG& dirSize,目錄大小,單位:位元組
    *Return      : pair<BOOL, string>,<函式是否執行成功,執行失敗時的錯誤資訊>
    *Caution     : 目錄末尾不能有斜槓,e.g. 正確傳參:/root/xxx,錯誤傳參:/root/xxx/
    */
    static pair<BOOL, string> getDirSize(IN const string& dirLongName, OUT DLONG& dirSize);

    /*
    *Function    : getDirSizeAndMaxFileSize
    *Description : 獲取目錄大小和其中最大檔案大小
    *Modify      : 2020.09.16
    *Input       : IN const string& dirLongName,目錄名
    *            : OUT DLONG& dirSize,目錄大小,單位:位元組
    *            : OUT DLONG& maxFileSize,目錄中最大檔案大小,單位:位元組
    *Return      : pair<BOOL, string>,<函式是否執行成功,執行失敗時的錯誤資訊>
    *Caution     : 目錄末尾不能有斜槓,e.g. 正確傳參:/root/xxx,錯誤傳參:/root/xxx/
    */
    static pair<BOOL, string> getDirSizeAndMaxFileSize(IN const string& dirLongName, OUT DLONG& dirSize, OUT DLONG& maxFileSize);

    /*
    *Function    : getFileSize
    *Description : 獲取檔案大小
    *Modify      : 2020.09.16
    *Input       : IN const string& fileLongName,檔名
    *            : OUT DLONG& fileSize,檔案大小
    *Return      : pair<BOOL, string>,<函式是否執行成功,執行失敗時的錯誤資訊>
    *Caution     :
    */
    static pair<BOOL, string> getFileSize(IN const string& fileLongName, OUT DLONG& fileSize);

    /*
    *Function    : getDiskSpace
    *Description : 獲取磁碟總容量和剩餘容量
    *Modify      : 2020.09.16
    *Input       : IN const string& diskPath,磁碟路徑,e.g. /root
    *            : OUT DLONG& totalSpace,磁碟總容量,單位:位元組
    *            : OUT DLONG& freeSpace,磁碟剩餘容量,單位:位元組
    *Return      : pair<BOOL, string>,<函式是否執行成功,執行失敗時的錯誤資訊>
    *Caution     :
    */
    static pair<BOOL, string> getDiskSpace(IN const string& diskPath, OUT DLONG& totalSpace, OUT DLONG& freeSpace);

    /*
    *Function    : getAllFileShortNamesInDir
    *Description : 獲取目錄下所有檔案的短檔名
    *Modify      : 2020.09.16
    *Input       : IN const string& dirLongName,目錄名
    *            : OUT vector<string>& allFileShortNames,目錄下所有檔案的短檔名
    *Return      : pair<BOOL, string>,<函式是否執行成功,執行失敗時的錯誤資訊>
    *Caution     : 目錄末尾不能有斜槓,e.g. 正確傳參:/root/xxx,錯誤傳參:/root/xxx/
    *            :
    */
    static pair<BOOL, string> getAllFileShortNamesInDir(IN const string& dirLongName, OUT vector<string>& allFileShortNames);

    /*
    *Function    : getAllFileLongNamesInDir
    *Description : 獲取目錄下所有檔案的長檔名
    *Modify      : 2020.09.16
    *Input       : IN const string& dirLongName,目錄名
    *            : OUT vector<string>& allFileLongNames,目錄下所有檔案的長檔名
    *Return      : pair<BOOL, string>,<函式是否執行成功,執行失敗時的錯誤資訊>
    *Caution     : 目錄末尾不能有斜槓,e.g. 正確傳參:/root/xxx,錯誤傳參:/root/xxx/
    *            :
    */
    static pair<BOOL, string> getAllFileLongNamesInDir(IN const string& dirLongName, OUT vector<string>& allFileLongNames);

    /*
    *Function    : moveFileOrDir
    *Description : 移動檔案或資料夾
    *Modify      : 2020.09.16
    *Input       : IN const string& srcLongName,原始檔(資料夾)名
    *            : IN const string& destLongName,目標檔案(資料夾)名
    *Return      : pair<BOOL, string>,<函式是否執行成功,執行失敗時的錯誤資訊>
    *Caution     : 如果 srcLongName 和 destLongName 指定相同的路徑,則進行重新命名操作
    *            : 如果 srcLongName 和 destLongName 指定不同的路徑,則檔案(資料夾)將移動到新位置
    *            : 如果 destLongName 為現有檔案,則覆蓋現有檔案
    *            : 如果 destLongName 為現有資料夾,則執行失敗
    */
    static pair<BOOL, string> moveFileOrDir(IN const string& srcLongName, IN const string& destLongName);

    /*
    *Function    : removeFile
    *Description : 刪除檔案
    *Modify      : 2020.09.15
    *Input       : IN const string& fileLongName,檔名
    *Return      : pair<BOOL, string>,<函式是否執行成功,執行失敗時的錯誤資訊>
    *Caution     :
    */
    static pair<BOOL, string> removeFile(IN const string& fileLongName);

    /*
    *Function    : removeDir
    *Description : 刪除目錄
    *Modify      : 2020.09.16
    *Input       : IN const string& dirLongName,目錄名
    *Return      : pair<BOOL, string>,<函式是否執行成功,執行失敗時的錯誤資訊>
    *Caution     : 目錄末尾不能有斜槓,e.g. 正確傳參:/root/xxx,錯誤傳參:/root/xxx/
    */
    static pair<BOOL, string> removeDir(IN const string& dirLongName);

    /*
    *Function    : copyFile
    *Description : 複製檔案
    *Modify      : 2020.09.16
    *Input       : IN const string& srcFileLongName,原始檔名
    *            : IN const string& destLongFileName,目標檔名
    *Return      : pair<BOOL, string>,<函式是否執行成功,執行失敗時的錯誤資訊>
    *Caution     :
    */
    static pair<BOOL, string> copyFile(IN const string& srcFileLongName, IN const string& destLongFileName);

    /*
    *Function    : copyDir
    *Description : 複製目錄
    *Modify      : 2020.09.15
    *Input       : IN const string& dirLongName,源目錄名
    *            : IN string& destDirPath,目標目錄名
    *Return      : pair<BOOL, string>,<函式是否執行成功,執行失敗時的錯誤資訊>
    *Caution     : 目錄末尾不能有斜槓,e.g. 正確傳參:/root/xxx,錯誤傳參:/root/xxx/
    *            :
    */
    static pair<BOOL, string> copyDir(IN const string& srcDirPath, IN const string& destDirPath);

    /*
    *Function    : truncateFile
    *Description : 截斷檔案
    *Modify      : 2020.09.15
    *Input       : IN const string& fileLongName,檔名
    *            : IN const DLONG len,檔案長度截斷為長度 len
    *Return      : pair<BOOL, string>,<函式是否執行成功,執行失敗時的錯誤資訊>
    *Caution     : 如果檔案先前大於此大小,則多餘的資料會丟失
    *            : 如果檔案先前較短,則將其擴充套件,擴充套件部分填充為空位元組('\0')
    *            : 截斷後 struct stat 的 st_size 變為 len
    */
    static pair<BOOL, string> truncateFile(IN const string& fileLongName, IN const DLONG len);

};    //FileOperation()

FileOperation.cpp

#include "FileOperation.h"

pair<BOOL, string> FileOperation::getDirSize(IN const string& dirLongName, OUT DLONG& dirSize)
{
    DIR* pDir = opendir(dirLongName.c_str());
    if (NULL != pDir)
    {
        struct dirent* pDirent = NULL;
        struct stat fileStat;
        string fileLongNameTmp;
        while (NULL != (pDirent = readdir(pDir)))
        {
            if (0 == strcmp(pDirent->d_name, ".") || 0 == strcmp(pDirent->d_name, ".."))
            {
                continue;
            }
            else if (DT_DIR != pDirent->d_type)
            {
                fileLongNameTmp = dirLongName + "/" + pDirent->d_name;
                if (0 == stat(fileLongNameTmp.c_str(), &fileStat))
                {
                    dirSize += fileStat.st_size;
                }
                else
                {
                    return make_pair(false, "file long name: " + fileLongNameTmp + ", error message: " + strerror(errno));
                }
            }
            else
            {
                pair<BOOL, string> exeStat = getDirSize(dirLongName + "/" + pDirent->d_name, dirSize);
                if (false == exeStat.first)
                {
                    return exeStat;
                }
            }
        }

        return make_pair(true, "");
    }
    else
    {
        return make_pair(false, "dir long name: " + dirLongName + ", error message: " + strerror(errno));
    }
}    //getDirSize()

pair<BOOL, string> FileOperation::getDirSizeAndMaxFileSize(IN const string& dirLongName, OUT DLONG& dirSize, OUT DLONG& maxFileSize)
{
    DIR* pDir = opendir(dirLongName.c_str());
    if (NULL != pDir)
    {
        struct dirent* pDirent = NULL;
        struct stat fileStat;
        string fileLongNameTmp;
        while (NULL != (pDirent = readdir(pDir)))
        {
            if (0 == strcmp(pDirent->d_name, ".") || 0 == strcmp(pDirent->d_name, ".."))
            {
                continue;
            }
            else if (DT_DIR != pDirent->d_type)
            {
                fileLongNameTmp = dirLongName + "/" + pDirent->d_name;
                if (0 == stat(fileLongNameTmp.c_str(), &fileStat))
                {
                    dirSize += fileStat.st_size;
                    if (fileStat.st_size > maxFileSize)
                    {
                        maxFileSize = fileStat.st_size;
                    }
                }
                else
                {
                    return make_pair(false, "file long name: " + fileLongNameTmp + ", error message: " + strerror(errno));
                }
            }
            else
            {
                pair<BOOL, string> exeStat = getDirSizeAndMaxFileSize(dirLongName + "/" + pDirent->d_name, dirSize, maxFileSize);
                if (false == exeStat.first)
                {
                    return exeStat;
                }
            }
        }

        return make_pair(true, "");
    }
    else
    {
        return make_pair(false, "dir long name: " + dirLongName + ", error message: " + strerror(errno));
    }
}    //getDirSizeAndMaxFileSize()

pair<BOOL, string> FileOperation::getFileSize(IN const string& fileLongName, OUT DLONG& fileSize)
{
    fileSize = 0;

    struct stat fileStat;
    if (0 == stat(fileLongName.c_str(), &fileStat))
    {
        fileSize = fileStat.st_size;
        return make_pair(true, "");
    }
    else
    {
        return make_pair(false, "file long name: " + fileLongName + ", error message: " + strerror(errno));
    }
}    //getFileSize()

pair<BOOL, string> FileOperation::getDiskSpace(IN const string& diskPath, OUT DLONG& totalSpace, OUT DLONG& freeSpace)
{
    totalSpace = 0;
    freeSpace = 0;

    struct statfs diskStatfs;
    if (statfs(diskPath.c_str(), &diskStatfs) >= 0)
    {
        totalSpace = (DLONG)diskStatfs.f_bsize * (DLONG)diskStatfs.f_blocks;
        freeSpace = (DLONG)diskStatfs.f_bsize * (DLONG)diskStatfs.f_bfree;
        return make_pair(true, "");
    }
    else
    {
        return make_pair(false, "disk path: " + diskPath + ", error message: " + strerror(errno));
    }
}    //getDiskSpace()

pair<BOOL, string> FileOperation::getAllFileShortNamesInDir(IN const string& dirLongName, OUT vector<string>& allFileShortNames)
{
    DIR* pDir = opendir(dirLongName.c_str());
    if (NULL != pDir)
    {
        struct dirent* pDirent = NULL;
        struct stat fileStat;
        while (NULL != (pDirent = readdir(pDir)))
        {
            if (0 == strcmp(pDirent->d_name, ".") || 0 == strcmp(pDirent->d_name, ".."))
            {
                continue;
            }
            else if (DT_DIR != pDirent->d_type)
            {
                allFileShortNames.emplace_back(pDirent->d_name);
            }
            else
            {
                pair<BOOL, string> exeStat = getAllFileShortNamesInDir(dirLongName + "/" + pDirent->d_name, allFileShortNames);
                if (false == exeStat.first)
                {
                    return exeStat;
                }
            }
        }

        return make_pair(true, "");
    }
    else
    {
        return make_pair(false, "dir long name: " + dirLongName + ", error message: " + strerror(errno));
    }
}    //getAllFileShortNamesInDir()

pair<BOOL, string> FileOperation::getAllFileLongNamesInDir(IN const string& dirLongName, OUT vector<string>& allFileLongNames)
{
    DIR* pDir = opendir(dirLongName.c_str());
    if (NULL != pDir)
    {
        struct dirent* pDirent = NULL;
        struct stat fileStat;
        while (NULL != (pDirent = readdir(pDir)))
        {
            if (0 == strcmp(pDirent->d_name, ".") || 0 == strcmp(pDirent->d_name, ".."))
            {
                continue;
            }
            else if (DT_DIR != pDirent->d_type)
            {
                allFileLongNames.emplace_back(dirLongName + "/" + pDirent->d_name);
            }
            else
            {
                pair<BOOL, string> exeStat = getAllFileLongNamesInDir(dirLongName + "/" + pDirent->d_name, allFileLongNames);
                if (false == exeStat.first)
                {
                    return exeStat;
                }
            }
        }

        return make_pair(true, "");
    }
    else
    {
        return make_pair(false, "dir long name: " + dirLongName + ", error message: " + strerror(errno));
    }
}    //getAllFileLongNamesInDir()

pair<BOOL, string> FileOperation::moveFileOrDir(IN const string& srcLongName, IN const string& destLongName)
{
    if (0 == rename(srcLongName.c_str(), destLongName.c_str()))
    {
        return make_pair(true, "");
    }
    else
    {
        return make_pair(false, "src file long name: " + srcLongName +
            ", dest file long name: " + destLongName + ", error message: " + strerror(errno));
    }
}    //moveFileOrDir()

pair<BOOL, string> FileOperation::removeFile(IN const string& fileLongName)
{
    if (0 == remove(fileLongName.c_str()))
    {
        return make_pair(true, "");
    }
    else
    {
        return make_pair(false, "file long name: " + fileLongName + ", error message: " + strerror(errno));
    }
}    //removeFile()

pair<BOOL, string> FileOperation::removeDir(IN const string& dirLongName)
{
    DIR* pDir = opendir(dirLongName.c_str());
    if (NULL != pDir)
    {
        struct dirent* pDirent = NULL;
        struct stat fileStat;
        while (NULL != (pDirent = readdir(pDir)))
        {
            if (0 == strcmp(pDirent->d_name, ".") || 0 == strcmp(pDirent->d_name, ".."))
            {
                continue;
            }
            else if (DT_DIR != pDirent->d_type)
            {
                pair<BOOL, string> exeStat = removeFile(dirLongName + "/" + pDirent->d_name);
                if (false == exeStat.first)
                {
                    return exeStat;
                }
            }
            else
            {
                pair<BOOL, string> exeStat = removeDir(dirLongName + "/" + pDirent->d_name);
                if (false == exeStat.first)
                {
                    return exeStat;
                }
            }
        }

        return make_pair(true, "");
    }
    else
    {
        return make_pair(false, "dir long name: " + dirLongName + ", error message: " + strerror(errno));
    }
}    //removeDir()

pair<BOOL, string> FileOperation::copyFile(IN const string& srcFileLongName, IN const string& destLongFileName)
{
    INT len = 0;
    FILE* pSrcFile = NULL;
    FILE* pDestFile = NULL;
    UINT bufferSize = 1 * 1024 * 1024;    //設定的過大也不會對效能有什麼顯著提升
    vector<CHAR> buffer(bufferSize, 0);

    if (NULL == (pSrcFile = fopen(srcFileLongName.c_str(), "rb")))
    {
        return make_pair(false, "source file long name: " + srcFileLongName + ", error message: " + strerror(errno));

    }
    if (NULL == (pDestFile = fopen(destLongFileName.c_str(), "wb")))
    {
        return make_pair(false, "dest file long name: " + destLongFileName + ", error message: " + strerror(errno));
    }

    while ((len = fread(&buffer[0], sizeof(BYTE), bufferSize, pSrcFile)) > 0)
    {
        fwrite(&buffer[0], sizeof(CHAR), len, pDestFile);
    }
    fclose(pDestFile);
    fclose(pSrcFile);

    return make_pair(true, "");
}    //copyFile()

pair<BOOL, string> FileOperation::copyDir(IN const string& srcDirPath, IN const string& destDirPath)
{
    if (0 != mkdir(destDirPath.c_str(), 00777))
    {
        return make_pair(false, "dest dir path: " + destDirPath + ", error message: " + strerror(errno));
    }

    DIR* pDir = opendir(srcDirPath.c_str());
    if (NULL != pDir)
    {
        struct dirent* pDirent = NULL;
        while (NULL != (pDirent = readdir(pDir)))
        {
            if (0 == strcmp(pDirent->d_name, ".") || 0 == strcmp(pDirent->d_name, ".."))
            {
                continue;
            }
            else if (DT_DIR != pDirent->d_type)
            {
                pair<BOOL, string> exeStat = copyFile(srcDirPath + "/" + pDirent->d_name, destDirPath + "/" + pDirent->d_name);
                if (false == exeStat.first)
                {
                    return exeStat;
                }
            }
            else
            {
                pair<BOOL, string> exeStat = copyDir(srcDirPath + "/" + pDirent->d_name, destDirPath + "/" + pDirent->d_name);
                if (false == exeStat.first)
                {
                    return exeStat;
                }
            }
        }

        return make_pair(true, "");
    }
    else
    {
        return make_pair(false, "source dir path: " + srcDirPath + ", error message: " + strerror(errno));
    }
}    //copyDir()

pair<BOOL, string> FileOperation::truncateFile(IN const string& fileLongName, IN const DLONG len)
{
    if (0 == truncate(fileLongName.c_str(), len))
    {
        return make_pair(true, "");
    }
    else
    {
        return make_pair(false, "file long name: " + fileLongName + ", error message: " + strerror(errno));
    }
}    //truncateFile()