307、Linux 的时间操作
UNIX 操作系统根据计算机产生的年代把 1970 年 1 月 1 日作为 UNIX 的纪元时间,1970 年 1 月 1
日是时间的中间点,将从 1970 年 1 月 1 日起经过的秒数用一个整数存放。
一、time_t 别名
time_t 用于表示时间类型,它是一个 long 类型的别名,在<time.h>文件中定义,表示从 1970 年 1
月 1 日 0 时 0 分 0 秒到现在的秒数。
typedef long time_t;
二、time()库函数
time()库函数用于获取操作系统的当前时间。
包含头文件:<time.h>
声明:
time_t time(time_t *tloc);
有两种调用方法:
time_t now=time(0); // 将空地址传递给 time()函数,并将 time()返回值赋给变量 now。
或
time_t now; time(&now); // 将变量 now 的地址作为参数传递给 time()函数。 三、tm 结构体
time_t 是一个长整数,不符合人类的使用习惯,需要转换成 tm 结构体,tm 结构体在<time.h>中声
明,如下: 2022-10-01 15:30:25 Oct 1,2022 15:30:25
struct tm
{
int tm_year; // 年份:其值等于实际年份减去 1900
int tm_mon; // 月份:取值区间为[0,11],其中 0 代表一月,11 代表 12 月
int tm_mday; // 日期:一个月中的日期,取值区间为[1,31]
int tm_hour; // 时:取值区间为[0,23]
int tm_min; // 分:取值区间为[0,59]
int tm_sec; // 秒:取值区间为[0,59]
int tm_wday; // 星期:取值区间为[0,6],其中 0 代表星期天,6 代表星期六
int tm_yday; // 从每年的 1 月 1 日开始算起的天数:取值区间为[0,365]
int tm_isdst; // 夏令时标识符,该字段意义不大
};
四、localtime()库函数
localtime()函数用于把 time_t 表示的时间转换为 tm 结构体表示的时间。
localtime()函数不是线程安全的,localtime_r()是线程安全的。
包含头文件:<time.h>
函数声明:
struct tm *localtime(const time_t *timep);
struct tm *localtime_r(const time_t *timep, struct tm *result);
示例:
#include <iostream>
#include <time.h> // 时间操作的头文件。
using namespace std;
int main()
{
time_t now=time(0); // 获取当前时间,存放在 now 中。
cout << "now=" << now << endl; // 显示当前时间,1970 年 1 月 1 日到现在的秒数。
tm tmnow;
localtime_r(&now,&tmnow); // 把整数的时间转换成 tm 结构体。
// 根据 tm 结构体拼接成中国人习惯的字符串格式。
string stime = to_string(tmnow.tm_year+1900)+"-" + to_string(tmnow.tm_mon+1)+"-" + to_string(tmnow.tm_mday)+" " + to_string(tmnow.tm_hour)+":" + to_string(tmnow.tm_min)+":" + to_string(tmnow.tm_sec);
cout << "stime=" << stime << endl;
}
五、mktime()库函数
mktime()函数的功能与 localtime()函数相反,用于把 tm 结构体时间转换为 time_t 时间。
包含头文件:<time.h>
函数声明:
time_t mktime(struct tm *tm);
该函数主要用于时间的运算,例如:把 2022-03-01 00:00:25 加 30 分钟。
思路:1)解析字符串格式的时间,转换成 tm 结构体;2)用 mktime()函数把 tm 结构体转换成 time_t
时间;3)把 time_t 时间加 30*60 秒;4)用 localtime_r()函数把 time_t 时间转换成 tm 结构体;5)把
tm 结构体转换成字符串。 六、gettimeofday()库函数
用于获取 1970 年 1 月 1 日到现在的秒和当前秒中已逝去的微秒数,可以用于程序的计时。
包含头文件:<sys/time.h>
函数声明:
int gettimeofday(struct timeval *tv, struct timezone *tz);
struct timeval {
time_t tv_sec; /* 1970-1-1 到现在的秒数 */
suseconds_t tv_usec; /* 当前秒中,已逝去的微秒数 */
};
struct timezone { /* 在实际开发中,派不上用场 */
int tz_minuteswest; /* minutes west of Greenwich */
int tz_dsttime; /* type of DST correction */
};
示例:
#include <iostream>
#include <sys/time.h> // gettimeofday()需要的头文件。
using namespace std;
int main()
{
timeval start,end;
gettimeofday(&start, 0 ); // 计时开始。
for (int ii=0;ii<1000000000;ii++)
;
gettimeofday(&end, 0 ); // 计时结束。
// 计算消耗的时长。
timeval tv;
tv.tv_usec=end.tv_usec-start.tv_usec;
tv.tv_sec=end.tv_sec-start.tv_sec;
if (tv.tv_usec<0)
{
tv.tv_usec=1000000-tv.tv_usec;
tv.tv_sec--;
}
cout << "耗时:" << tv.tv_sec << "秒和" << tv.tv_usec << "微秒。\n";
}
七、程序睡眠
如果需要把程序挂起一段时间,可以使用 sleep()和 usleep()两个库函数。
包含头文件:<unistd.h>
函数声明:
unsigned int sleep(unsigned int seconds);
int usleep(useconds_t usec);
308、Linux 的目录操作
一、几个简单的目录操作函数
1)获取当前工作目录
包含头文件:<unistd.h>
char *getcwd(char *buf, size_t size);
char *get_current_dir_name(void);
示例:
#include <iostream>
#include <unistd.h>
using namespace std;
int main()
{
char path1[256]; // linux 系统目录的最大长度是 255。
getcwd(path1,256);
cout << "path1=" << path1 << endl;
char *path2=get_current_dir_name();
cout << "path2=" << path2 << endl;
free(path2); // 注意释放内存。malloc() new delete
}
2)切换工作目录
包含头文件:<unistd.h>
int chdir(const char *path);
返回值:0-成功;其它-失败(目录不存在或没有权限)。
3)创建目录
包含头文件:<sys/stat.h>
int mkdir(const char *pathname, mode_t mode);
pathname-目录名。
mode-访问权限,如 0755,不要省略前置的 0。
返回值:0-成功;其它-失败(上级目录不存在或没有权限)。 /tmp/aaa /tmp/aaa/bbb
4)删除目录
包含头文件: <unistd.h>
int rmdir(const char *path);
path-目录名。
返回值:0-成功;其它-失败(目录不存在或没有权限)。 二、获取目录中文件的列表
文件存放在目录中,在处理文件之前,必须先知道目录中有哪些文件,所以要获取目录中文件的列表。
1)包含头文件
#include <dirent.h>
2)相关的库函数
步骤一:用 opendir()函数打开目录。
DIR *opendir(const char *pathname);
成功-返回目录的地址,失败-返回空地址。
步骤二:用 readdir()函数循环的读取目录。
struct dirent *readdir(DIR *dirp);
成功-返回 struct dirent 结构体的地址,失败-返回空地址。
步骤三:用 closedir()关闭目录。
int closedir(DIR *dirp);
3)数据结构
目录指针:
DIR *目录指针变量名;
每次调用 readdir(),函数返回 struct dirent 的地址,存放了本次读取到的内容。
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 [NAME_MAX+1]; // file name 文件名,最长 255 字符。
};
重点关注结构体的 d_name 和 d_type 成员。
d_name-文件名或目录名。
d_type-文件的类型,有多种取值,最重要的是 8 和 4,8-常规文件(A regular file);4-子目录(A
directory),其它的暂时不关心。注意,d_name 的数据类型是字符,不可直接显示。
示例:
#include <iostream>
#include <dirent.h>
using namespace std;
int main(int argc,char *argv[])
{
if (argc != 2) { cout << "Using ./demo 目录名\n"; return -1; }
DIR *dir; // 定义目录指针。
// 打开目录。
if ( (dir=opendir(argv[1])) == nullptr ) return -1;
// 用于存放从目录中读取到的内容。
struct dirent *stdinfo=nullptr;
while (1)
{
// 读取一项内容并显示出来。
if ((stdinfo=readdir(dir)) == nullptr) break;
cout << "文件名=" << stdinfo->d_name << ",文件类型=" << (int)stdinfo->d_type <<
endl;
}
closedir(dir); // 关闭目录指针。
}