windows 遍历目录及删除限时文件

最近因为测试目的需要遍历一个目录下面的所有文件进行操作,主要是读每个文件的内容,只要知道文件名就OK了。在Java中直接用File类就可以搞定,因为Java中使用了组合模式,使得客户端对单个文件和文件夹的使用具有一致性,非常方便。但在C中就不一样了,而且在不同的平台下使用方法也不同。在Linux下实现该功能就非常方便,因为自带有API库,几个函数用起来得心应手(虽然有些小问题,后面说),在Windows下实现就不是那么方便,虽然也有自己的API,但用法有些晦涩难懂,因为没有封装起来,需要自己一步一步进行操作,因为用的是Windows API库函数所以如果对Windows编程不熟悉的话,照搬网上的代码错了也不易调试。为此,我把这些操作都封装成类似Linux下的库函数,一方面简化透明了操作,另一方面(也许更重要)就是移植性,这样将包含该功能的程序从Windows上移植到Linux下就无需改动代码了(删掉实现封装的文件,因为Linux下自带了),当然从Linux下移植到Windows下同样方便(增加实现封装的文件即可),这就是所谓的OCP原则吧(开放封闭原则,具体见:程序员该有的艺术气质—SOLID原则)。好了,首先看下Linux下是如何实现这个功能的。

 一、Linux下实现目录操作的API函数都在头文件dirent.h中,截取部分该文件内容如下:

/** structure describing an open directory. */
typedef struct _dirdesc {
    int    dd_fd;          /** file descriptor associated with directory */
    long    dd_loc;        /** offset in current buffer */
    long    dd_size;       /** amount of data returned by getdirentries */
    char    *dd_buf;       /** data buffer */
    int    dd_len;         /** size of data buffer */
    long    dd_seek;       /** magic cookie returned by getdirentries */
    long    dd_rewind;     /** magic cookie for rewinding */
    int    dd_flags;       /** flags for readdir */
    struct pthread_mutex    *dd_lock;    /** lock */
    struct _telldir *dd_td;    /** telldir position recording */
} DIR;

typedef    void *    DIR;

DIR    *opendir(const char *);
DIR    *fdopendir(int);
struct dirent *readdir(DIR *);
void     seekdir(DIR *, long);
long     telldir(DIR *);
void     rewinddir(DIR *);
int     closedir(DIR *);

struct dirent
{
     long d_ino;              /* inode number*/
     off_t d_off;             /* offset to this dirent*/
     unsigned short d_reclen; /* length of this d_name*/
     unsigned char d_type;    /* the type of d_name*/
     char d_name[1];          /* file name (null-terminated)*/
};

测试 main.c

#include  
#include     
#include   
#include  

#define MAX_LEN 65535

int main(void) 
{ 
    DIR *dir; 
    struct dirent *ptr; 
    char *flow[MAX_LEN];    //指针数组 每个元素是指向文件名的指针
    int num = 0, i = 0;
   
    if ((dir=opendir("./data")) == NULL) 
    { 
        perror("Open dir error..."); 
        exit(1);        
    } 
    // readdir() return next enter point of directory dir
    while ((ptr=readdir(dir)) != NULL) 
    { 
        flow[num++] = ptr->d_name;
//      printf("%s\n", flow[num - 1]);

        //flow[num] = (char*)malloc(sizeof(char));
        //strcpy(flow[num], ptr->d_name);
        //num++;

    } 

    for(i = 0; i < num; i++)
    {
        printf("%s\n", flow[i]);
    }
   
    closedir(dir); 
}

二、Windows 下遍历目录的方法

1. 首先模拟Linux下自带的头文件dirent.h

// dirent.h
#ifndef _SYS_DIRENT_H
#define _SYS_DIRENT_H

typedef struct _dirdesc {
	int     dd_fd;      /** file descriptor associated with directory */
	long    dd_loc;     /** offset in current buffer */
	long    dd_size;    /** amount of data returned by getdirentries */
	char    *dd_buf;    /** data buffer */
	int     dd_len;     /** size of data buffer */
	long    dd_seek;    /** magic cookie returned by getdirentries */
} DIR;

# define __dirfd(dp)    ((dp)->dd_fd)

DIR *opendir(const char *);
struct dirent *readdir(DIR *);
void rewinddir(DIR *);
int closedir(DIR *);

#include 

struct dirent
{
	long d_ino;              /* inode number*/
	off_t d_off;             /* offset to this dirent*/
	unsigned short d_reclen; /* length of this d_name*/
	unsigned char d_type;    /* the type of d_name*/
	char d_name[1];          /* file name (null-terminated)*/
};

#endif

2、dirent.cpp

// dirent.c
#include      
#include   
#include "dirent.h"

static HANDLE hFind;

DIR *opendir(const char *name)
{
	DIR *dir;
	WIN32_FIND_DATAA FindData;
	char namebuf[512];

	sprintf(namebuf, "%s\\*.*", name);
	printf("%s\n", namebuf);
	//hFind = FindFirstFile((LPCWSTR)namebuf, &FindData);  // 该函数调试不行
	hFind = FindFirstFileA((LPCSTR)namebuf, &FindData);
	if (hFind == INVALID_HANDLE_VALUE)
	{
		printf("FindFirstFile failed (%d)\n", GetLastError());
		system("pause");
		return 0;
	}

	dir = (DIR *)malloc(sizeof(DIR));
	if (!dir)
	{
		printf("DIR memory allocate fail\n");
		return 0;
	}

	memset(dir, 0, sizeof(DIR));
	dir->dd_fd = 0;   // simulate return  

	return dir;
}

struct dirent *readdir(DIR *d)
{
	int i;
    static struct dirent dirent;
	BOOL bf;
	WIN32_FIND_DATA FileData;
	if (!d)
	{
		return 0;
	}

	bf = FindNextFile(hFind, &FileData);
	//fail or end  
	if (!bf)
	{
		return 0;
	}

	for (i = 0; i < 256; i++)
	{
		dirent.d_name[i] = FileData.cFileName[i];
		if (FileData.cFileName[i] == '\0') break;
	}
	dirent.d_reclen = i;
	dirent.d_reclen = FileData.nFileSizeLow;

	//check there is file or directory  
	if (FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
	{
		dirent.d_type = 2;
	}
	else
	{
		dirent.d_type = 1;
	}


	return (&dirent);
}

int closedir(DIR *d)
{
	if (!d) return -1;
	hFind = 0;
	free(d);
	return 0;
}

main.cc

#include "dirent.h" 
#include "timestamp.h"

#include  
#include     
#include 
#include 

#include 
#include 
#include 

using namespace std;

#define MAX_LEN 65535

int main(void)
{
	DIR *dir;
	struct dirent *dir_item;
	char *flow[MAX_LEN];
	int num = 0, i = 0;
	
	string logpath_ = ".\\log";
	//static const int log_life = 30 * 24 * 3600;
	static const int log_life = 2*60;   // 1 min

	printf("before opendir\n");

	if ((dir = opendir(logpath_.c_str())) == NULL)
	{
		perror("Open dir error...");
		system("pause");
		exit(1);
	}
	printf("before readdir\n");
	// readdir() return next enter point of directory dir
	while ((dir_item = readdir(dir)) != NULL)
	{
		//flow[num++] = ptr->d_name;
		//strcpy(flow[num++], ptr->d_name);
		//printf("%s\n", flow[num - 1]);
		//printf("num: %d\n", num);
		if (strstr(dir_item->d_name, ".log") == NULL)
		{
			continue;
		}

		char file[128] = { 0 };
		sprintf(file, "%s\\%s", logpath_.c_str(), dir_item->d_name);

		printf("file: %s\n", file);
		//system("pause");

		struct _stat file_attr;
		int ret = _stat(file, &file_attr);
		if (ret < 0)
		{
			printf("stat '%s' failed.\n", file);
			continue;
		}

		if ((file_attr.st_mode & S_IFMT) != S_IFREG)
		{
			printf("S_IFREG\n");
			continue;
		}

		printf("second = %d\n", TimeStamp::now().Seconds());
		printf("st_mtime = %d\n", file_attr.st_mtime);
#if 1
		/* 超过若干天 */
		if (TimeStamp::now().Seconds() - file_attr.st_mtime > log_life)
		{
			printf("remove file '%s'\n", file);
			remove(file);
		}
#endif
		num++;
		printf("while....\n");
	}

	printf("num = %d\n", num);

	closedir(dir);


	system("pause");
}

 

三、附带timestamp.h

#ifndef BASE_TIMESTAMP_H
#define BASE_TIMESTAMP_H

#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

#ifdef WIN32	
#define snprintf _snprintf
#endif

class TimeStamp
{
public:
	TimeStamp(int32_t seconds = 0, int32_t microseconds = 0)
		: seconds_(seconds), microseconds_(microseconds)
	{

	}

	int32_t Seconds()
	{
		return seconds_;
	}

	int32_t MilliSeconds()
	{
		return microseconds_ / kMicroSecondsPerMilliSecond;
	}

	int32_t MicroSeconds()
	{
		return microseconds_;
	}

	string ToString();
	string ToFormattedString(bool show_microseconds = true);

	static TimeStamp now();

	static const int kMilliSecondsPerSecond = 1000;
	static const int kMicroSecondsPerSecond = 1000000;
	static const int kMicroSecondsPerMilliSecond = 1000;

private:
	int32_t seconds_;
	int32_t microseconds_;
};

#endif //BASE_TIMESTAMP_H

timestamp.cpp

#include "timestamp.h"

#include 
#include 

#ifdef WIN32
#include 
#else
#include 
#endif

#ifdef WIN32
int gettimeofday(struct timeval *tp, void *tzp)
{
	time_t clock;
	struct tm tm;
	SYSTEMTIME wtm;

	GetLocalTime(&wtm);
	tm.tm_year = wtm.wYear - 1900;
	tm.tm_mon = wtm.wMonth - 1;
	tm.tm_mday = wtm.wDay;
	tm.tm_hour = wtm.wHour;
	tm.tm_min = wtm.wMinute;
	tm.tm_sec = wtm.wSecond;
	tm.tm_isdst = -1;
	clock = mktime(&tm);
	tp->tv_sec = clock;
	tp->tv_usec = wtm.wMilliseconds * 1000;

	return (0);
}
#endif

string TimeStamp::ToString()
{
	char buf[32] = { 0 };
	snprintf(buf, sizeof(buf), "%d.%06d", seconds_, microseconds_);

	return buf;
}

string TimeStamp::ToFormattedString(bool show_microseconds)
{
	char buf[64] = { 0 };
	struct tm tm_time;
	time_t t = static_cast(seconds_);
#if 0
	/* gmtime转出来的是0时区的标准时间 */
	gmtime_r(&t, &tm_time);
#else
	/* localtime是将时区考虑在内了,转出当前时区的时间 */
	localtime_s(&tm_time, &t);
#endif

	if (show_microseconds)
	{
		snprintf(buf, sizeof(buf), "%04d-%02d-%02d %02d:%02d:%02d.%06d",
			tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday,
			tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, microseconds_);
	}
	else
	{
		snprintf(buf, sizeof(buf), "%04d-%02d-%02d %02d:%02d:%02d",
			tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday,
			tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec);
	}

	return buf;
}

TimeStamp TimeStamp::now()
{
	struct timeval tv;
	gettimeofday(&tv, NULL);

	return TimeStamp(static_cast(tv.tv_sec), static_cast(tv.tv_usec));
}

 

你可能感兴趣的:(Windows)