开发工具-目录相关操作类与函数

125 阅读5分钟

目录操作相关的类

根据绝对路径的文件名或目录名逐级的创建目录。

// pathorfilename:绝对路径的文件名或目录名。
// bisfilename:说明pathorfilename的类型,true-pathorfilename是文件名,否则是目录名,缺省值为true。
// 返回值:true-成功,false-失败,如果返回失败,原因有大概有三种情况:1)权限不足;2)pathorfilename参数不是合法的文件名或目录名;3)磁盘空间不足。
bool MKDIR(const char *pathorfilename,bool bisfilename=true);
bool MKDIR(const char *filename,bool bisfilename)
{
  // 检查目录是否存在,如果不存在,逐级创建子目录
  char strPathName[301];
  int ilen=strlen(filename);
  for (int ii=1; ii<ilen;ii++)
  {
    if (filename[ii] != '/') continue;
    STRNCPY(strPathName,sizeof(strPathName),filename,ii);
    if (access(strPathName,F_OK) == 0) continue; // 如果目录已存在,continue
    if (mkdir(strPathName,0755) != 0) return false;  // 如果目录不存在,创建它。
  }
  if (bisfilename==false)
  {
    if (access(filename,F_OK) != 0)
    {
      if (mkdir(filename,0755) != 0) return false;
    }
  }
  return true;
}

int main()
{
  MKDIR("/tmp/aaa/bbb/ccc/ddd",false);   // 创建"/tmp/aaa/bbb/ccc/ddd"目录。
  MKDIR("/tmp/111/222/333/444/data.xml",true);   // 创建"/tmp/111/222/333/444"目录。
}

获取某目录及其子目录中的文件列表信息。

class CDir
{
public:
  char m_DirName[301];        // 目录名,例如:/tmp/root。
  char m_FileName[301];       // 文件名,不包括目录名,例如:data.xml。
  char m_FullFileName[301];   // 文件全名,包括目录名,例如:/tmp/root/data.xml。
  int  m_FileSize;            // 文件的大小,单位:字节。
  char m_ModifyTime[21];      // 文件最后一次被修改的时间,即stat结构体的st_mtime成员。
  char m_CreateTime[21];      // 文件生成的时间,即stat结构体的st_ctime成员。
  char m_AccessTime[21];      // 文件最后一次被访问的时间,即stat结构体的st_atime成员。
  char m_DateFMT[25];         // 文件时间显示格式,由SetDateFMT方法设置。

  vector<string> m_vFileName; // 存放OpenDir方法获取到的绝对路径文件名清单。
  int m_pos;                  // 已读取m_vFileName容器的位置,每调用一次ReadDir方法m_pos加1。

  CDir();  // 构造函数。
  void initdata(); // 初始化成员变量。

  // 设置文件时间的格式,支持"yyyy-mm-dd hh24:mi:ss"和"yyyymmddhh24miss"两种,缺省是前者。
  void SetDateFMT(const char *in_DateFMT);

  // 打开目录,获取目录中的文件列表信息,存放于m_vFileName容器中。
  // in_DirName,待打开的目录名,采用绝对路径,如/tmp/root。
  // in_MatchStr,待获取文件名的匹配规则,不匹配的文件被忽略,具体请参见开发框架的MatchStr函数。
  // in_MaxCount,获取文件的最大数量,缺省值为10000个。
  // bAndChild,是否打开各级子目录,缺省值为false-不打开子目录。
  // bSort,是否对获取到的文件列表(即m_vFileName容器中的内容)进行排序,缺省值为false-不排序。
  // 返回值:true-成功,false-失败,如果in_DirName参数指定的目录不存在,OpenDir方法会创建该目录,如果创建失败,返回false,如果当前用户对in_DirName目录下的子目录没有读取权限也会返回false。
  bool OpenDir(const char *in_DirName,const char *in_MatchStr,const unsigned int in_MaxCount=10000,const bool bAndChild=false,bool bSort=false);

  // 这是一个递归函数,被OpenDir()的调用,在CDir类的外部不需要调用它。
  bool _OpenDir(const char *in_DirName,const char *in_MatchStr,const unsigned int in_MaxCount,const bool bAndChild);

  // 从m_vFileName容器中获取一条记录(文件名),同时获取该文件的大小、修改时间等信息。
  // 调用OpenDir方法时,m_vFileName容器被清空,m_pos归零,每调用一次ReadDir方法m_pos加1。
  // 当m_pos小于m_vFileName.size(),返回true,否则返回false。
  bool ReadDir();

  ~CDir();  // 析构函数。
};

---cpp

CDir::CDir()
{
  m_pos=0;
  STRCPY(m_DateFMT,sizeof(m_DateFMT),"yyyy-mm-dd hh24:mi:ss");
  m_vFileName.clear();
  initdata();
}

void CDir::initdata()
{
  memset(m_DirName,0,sizeof(m_DirName));
  memset(m_FileName,0,sizeof(m_FileName));
  memset(m_FullFileName,0,sizeof(m_FullFileName));
  m_FileSize=0;
  memset(m_CreateTime,0,sizeof(m_CreateTime));
  memset(m_ModifyTime,0,sizeof(m_ModifyTime));
  memset(m_AccessTime,0,sizeof(m_AccessTime));
}

// 设置文件时间的格式,支持"yyyy-mm-dd hh24:mi:ss"和"yyyymmddhh24miss"两种,缺省是前者。
void CDir::SetDateFMT(const char *in_DateFMT)
{
  memset(m_DateFMT,0,sizeof(m_DateFMT));
  STRCPY(m_DateFMT,sizeof(m_DateFMT),in_DateFMT);
}

// 打开目录,获取目录中的文件列表信息,存放于m_vFileName容器中。
// in_DirName,待打开的目录名。
// in_MatchStr,待获取文件名的匹配规则,不匹配的文件被忽略。
// in_MaxCount,获取文件的最大数量,缺省值为10000个。
// bAndChild,是否打开各级子目录,缺省值为false-不打开子目录。
// bSort,是否对获取到的文件列表(即m_vFileName容器中的内容)进行排序,缺省值为false-不排序。
// 返回值:如果in_DirName参数指定的目录不存在,OpenDir方法会创建该目录,如果创建失败,返回false,还有,如果当前用户对in_DirName目录下的子目录没有读取权限也会返回false,其它正常情况下都会返回true。
bool CDir::OpenDir(const char *in_DirName,const char *in_MatchStr,const unsigned int in_MaxCount,const bool bAndChild,bool bSort)
{
  m_pos=0;
  m_vFileName.clear();

  // 如果目录不存在,就创建该目录
  if (MKDIR(in_DirName,false) == false) return false;
  bool bRet=_OpenDir(in_DirName,in_MatchStr,in_MaxCount,bAndChild);
  if (bSort==true)
  {
    sort(m_vFileName.begin(), m_vFileName.end());
  }
  return bRet;
}

// 这是一个递归函数,用于OpenDir()的调用,在CDir类的外部不需要调用它。
bool CDir::_OpenDir(const char *in_DirName,const char *in_MatchStr,const unsigned int in_MaxCount,const bool bAndChild)
{
  DIR *dir;
  if ( (dir=opendir(in_DirName)) == 0 ) return false;
  char strTempFileName[3001];
  struct dirent *st_fileinfo;
  struct stat st_filestat;
  while ((st_fileinfo=readdir(dir)) != 0)
  {
    // 以"."打头的文件不处理
    if (st_fileinfo->d_name[0]=='.') continue;   
    SNPRINTF(strTempFileName,sizeof(strTempFileName),300,"%s//%s",in_DirName,st_fileinfo->d_name);
    UpdateStr(strTempFileName,"//","/");
    stat(strTempFileName,&st_filestat);

    // 判断是否是目录,如果是,处理各级子目录。
    if (S_ISDIR(st_filestat.st_mode))
    {
      if (bAndChild == true)
      {
        if (_OpenDir(strTempFileName,in_MatchStr,in_MaxCount,bAndChild) == false) 
        {
          closedir(dir); return false;
        }
      }
    }
    else
    {
      // 如果是文件,把能匹配上的文件放入m_vFileName容器中。
      if (MatchStr(st_fileinfo->d_name,in_MatchStr) == false) continue;
      m_vFileName.push_back(strTempFileName);
      if ( m_vFileName.size()>=in_MaxCount ) break;
    }
  }
  closedir(dir);
  return true;
}

/*
st_gid 
  Numeric identifier of group that owns file (UNIX-specific) This field will always be zero on NT systems. A redirected file is classified as an NT file.
st_atime
  Time of last access of file.
st_ctime
  Time of creation of file.
st_dev
  Drive number of the disk containing the file (same as st_rdev).
st_ino
  Number of the information node (the inode) for the file (UNIX-specific). On UNIX file systems, the inode describes the file date and time stamps, permissions, and content. When files are hard-linked to one another, they share the same inode. The inode, and therefore st_ino, has no meaning in the FAT, HPFS, or NTFS file systems.
st_mode
  Bit mask for file-mode information. The _S_IFDIR bit is set if path specifies a directory; the _S_IFREG bit is set if path specifies an ordinary file or a device. User read/write bits are set according to the file’s permission mode; user execute bits are set according to the filename extension.
st_mtime
  Time of last modification of file.
st_nlink
  Always 1 on non-NTFS file systems.
st_rdev
  Drive number of the disk containing the file (same as st_dev).
st_size
  Size of the file in bytes; a 64-bit integer for _stati64 and _wstati64
st_uid
  Numeric identifier of user who owns file (UNIX-specific). This field will always be zero on NT systems. A redirected file is classified as an NT file.
*/

// 从m_vFileName容器中获取一条记录(文件名),同时得到该文件的大小、修改时间等信息。
// 调用OpenDir方法时,m_vFileName容器被清空,m_pos归零,每调用一次ReadDir方法m_pos加1。
// 当m_pos小于m_vFileName.size(),返回true,否则返回false。
bool CDir::ReadDir()
{
  initdata();
  int ivsize=m_vFileName.size();

  // 如果已读完,清空容器
  if (m_pos >= ivsize) 
  {
    m_pos=0; m_vFileName.clear(); return false;
  }

  int pos=0;
  pos=m_vFileName[m_pos].find_last_of("/");
  
  // 目录名
  STRCPY(m_DirName,sizeof(m_DirName),m_vFileName[m_pos].substr(0,pos).c_str());

  // 文件名
  STRCPY(m_FileName,sizeof(m_FileName),m_vFileName[m_pos].substr(pos+1,m_vFileName[m_pos].size()-pos-1).c_str());

  // 文件全名,包括路径
  SNPRINTF(m_FullFileName,sizeof(m_FullFileName),300,"%s",m_vFileName[m_pos].c_str());

  struct stat st_filestat;
  stat(m_FullFileName,&st_filestat);
  m_FileSize=st_filestat.st_size;
  struct tm nowtimer;

  if (strcmp(m_DateFMT,"yyyy-mm-dd hh24:mi:ss") == 0)
  {
    nowtimer = *localtime(&st_filestat.st_mtime);
    // localtime_r(&st_filestat.st_mtime,&nowtimer); 
    nowtimer.tm_mon++;
    snprintf(m_ModifyTime,20,"%04u-%02u-%02u %02u:%02u:%02u",\
             nowtimer.tm_year+1900,nowtimer.tm_mon,nowtimer.tm_mday,\
             nowtimer.tm_hour,nowtimer.tm_min,nowtimer.tm_sec);

    nowtimer = *localtime(&st_filestat.st_ctime);
    // localtime_r(&st_filestat.st_ctime,&nowtimer); 
    nowtimer.tm_mon++;
    snprintf(m_CreateTime,20,"%04u-%02u-%02u %02u:%02u:%02u",\
             nowtimer.tm_year+1900,nowtimer.tm_mon,nowtimer.tm_mday,\
             nowtimer.tm_hour,nowtimer.tm_min,nowtimer.tm_sec);

    nowtimer = *localtime(&st_filestat.st_atime);
    // localtime_r(&st_filestat.st_atime,&nowtimer); 
    nowtimer.tm_mon++;
    snprintf(m_AccessTime,20,"%04u-%02u-%02u %02u:%02u:%02u",\
             nowtimer.tm_year+1900,nowtimer.tm_mon,nowtimer.tm_mday,\
             nowtimer.tm_hour,nowtimer.tm_min,nowtimer.tm_sec);
  }

  if (strcmp(m_DateFMT,"yyyymmddhh24miss") == 0)
  {
    nowtimer = *localtime(&st_filestat.st_mtime);
    // localtime_r(&st_filestat.st_mtime,&nowtimer); 
    nowtimer.tm_mon++;
    snprintf(m_ModifyTime,20,"%04u%02u%02u%02u%02u%02u",\
             nowtimer.tm_year+1900,nowtimer.tm_mon,nowtimer.tm_mday,\
             nowtimer.tm_hour,nowtimer.tm_min,nowtimer.tm_sec);

    nowtimer = *localtime(&st_filestat.st_ctime);
    // localtime_r(&st_filestat.st_ctime,&nowtimer); 
    nowtimer.tm_mon++;
    snprintf(m_CreateTime,20,"%04u%02u%02u%02u%02u%02u",\
             nowtimer.tm_year+1900,nowtimer.tm_mon,nowtimer.tm_mday,\
             nowtimer.tm_hour,nowtimer.tm_min,nowtimer.tm_sec);

    nowtimer = *localtime(&st_filestat.st_atime);
    // localtime_r(&st_filestat.st_atime,&nowtimer); 
    nowtimer.tm_mon++;
    snprintf(m_AccessTime,20,"%04u%02u%02u%02u%02u%02u",\
             nowtimer.tm_year+1900,nowtimer.tm_mon,nowtimer.tm_mday,\
             nowtimer.tm_hour,nowtimer.tm_min,nowtimer.tm_sec);
  }

  m_pos++;
  return true;
}

CDir::~CDir()
{
  m_vFileName.clear();
  // m_vDirName.clear();
}

---测试
int main(int argc,char *argv[])
{
  if (argc != 2) { printf("请指定目录名。\n"); return -1; }
  CDir Dir;

  if (Dir.OpenDir(argv[1],"*.h,*cpp",100,true,true)==false)
  { 
    printf("Dir.OpenDir(%s) failed.\n",argv[1]); return -1; 
  }

  while(Dir.ReadDir()==true)
  {
    printf("filename=%s,mtime=%s,size=%d\n",Dir.m_FullFileName,Dir.m_ModifyTime,Dir.m_FileSize);
  }
}