Linux的文件和时间操作

Linux时间操作

UNIX操作系统根据计算机产生的年代把1970年1月1日作为UNIX的纪元时间,1970年1月1日是时间的中间点,将从1970年1月1日起经过的秒数用一个整数存放。

time_t

time_t用于表示时间类型,它是long类型。表示从1970年1月1日0时0分0秒到现在的秒数。

time()

time()用于获取操作系统当前时间。

#include <time.h>
#include <iostream>

using namespace std;

int main()
{
    time_t now=time(0);
    cout << now << endl;
    time_t now2;
    time(&now2);
    cout << now2 << endl;
    return 0;
}

tm结构体

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()是线程安全的。

函数声明

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_t mktime(struct tm *tm)

比如说把2022-02-28 24:00:00加30分钟,手写还要考虑闰年、进位等等问题,可以用mktime()当中间跳板先变秒数,加了再用localtime转成结构体。

#include <iostream>
#include <time.h>

using namespace std;

//把2022-02-28 24:00:00加30分钟
int main()
{
    struct tm mytime;
    mytime.tm_year = 2022 - 1900;
    mytime.tm_mon = 2 - 1;
    mytime.tm_mday = 28;
    mytime.tm_hour = 24;
    mytime.tm_min = 0;
    mytime.tm_sec = 0;

    time_t tmp = mktime(&mytime);
    tmp += 30 * 60;

    localtime_r(&tmp, &mytime);
    string stime = to_string(mytime.tm_year+1900)+"-"
                + to_string(mytime.tm_mon+1)+"-"
                + to_string(mytime.tm_mday)+" "
                + to_string(mytime.tm_hour)+":"
                + to_string(mytime.tm_min)+":"
                + to_string(mytime.tm_sec);
    cout << "加了30分钟后: " << stime << endl;

    return 0;
}

gettimeofday()

用于获取1970年1月1日到现在的秒和当前秒中已逝去的微秒数

#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";
}

程序睡眠

包含头文件:<unistd.h>

sleep是秒,usleep是微秒(百万分之一秒)

unsigned int sleep(unsigned int seconds);
int usleep(useconds_t usec);

Linux的目录操作

简单的目录操作函数

1) 获取当前工作目录

包含头文件:<unistd.h>
char *getcwd(char *buf, size_t size); 
char *get_current_dir_name(void);

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-成功;其它-失败(目录不存在或没有权限)。

4)删除目录

包含头文件: <unistd.h>
int rmdir(const char *path);
返回值:0-成功;其它-失败(目录不存在或没有权限)。

示例:

#include <iostream>
#include <cstring>
#include <unistd.h>
#include <sys/stat.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

    // 在当前目录下创建test1目录,切换进test1目录后创建test2目录
    char path3[256];
    strcpy(path3, path1);
    strcat(path3, "/test1");
    mkdir(path3, 0755);

    chdir(path3);
    char path4[256];
    strcpy(path4, path3);
    strcat(path4, "/test2");
    mkdir(path4, 0775);

    // 然后删除test2目录
    rmdir(path4);
}

获取目录中文件的列表

每次调用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);   // 关闭目录指针。
}

Linux的系统错误

strerror()

strerror() 在<string.h>中声明,用于获取错误代码对应的详细信息。
char *strerror(int errnum);                         // 非线程安全。
int strerror_r(int errnum, char *buf, size_t buflen);       // 线程安全。

gcc8.3.1目前有133个错误代码

#include <iostream>
#include <cstring>
using namespace std;

int main()
{
  int ii;

  for(ii=0;ii<150;ii++)      // gcc8.3.1一共有133个错误代码。
  {
    cout << ii << ":" << strerror(ii) << endl;
  }
}

perror()

perror() 在<stdio.h>中声明,用于在控制台显示最近一次系统错误的详细信息,在实际开发中,服务程序在后台运行,通过控制台显示错误信息意义不大。(对调试程序略有帮助)

void perror(const char *s);

注意

1)调用库函数失败不一定会设置errno
并不是全部的库函数在调用失败时都会设置errno的值,以man手册为准(一般来说,不属于系统调用的函数不会设置errno,属于系统调用的函数才会设置errno)。什么是系统调用?百度“库函数和系统调用的区别”。

2)errno不能作为调用库函数失败的标志
errno的值只有在库函数调用发生错误时才会被设置,当库函数调用成功时,errno的值不会被修改,不会主动的置为 0。
在实际开发中,判断函数执行是否成功还得靠函数的返回值,只有在返回值是失败的情况下,才需要关注errno的值。

#include <iostream>
#include <cstring>    // strerror()函数需要的头文件。
#include <cerrno>     // errno全局变量的头文件。
#include <sys/stat.h> // mkdir()函数需要的头文件。
using namespace std;

int main()
{
    int iret = mkdir("/tmp/aaa/bb/cc/dd", 0755);
    if (iret != 0)
    {
        cout << "iret=" << iret << endl;
        cout << errno << ":" << strerror(errno) << endl;
        perror("调用mkdir(/tmp/aaa/bb/cc/dd)失败");
    }

    iret = mkdir("/tmp/dd", 0755);
    if (iret != 0)
    {
        cout << "iret=" << iret << endl;
        cout << errno << ":" << strerror(errno) << endl;
        perror("调用mkdir(/tmp/dd)失败");
    }
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇