futimens, utimensat, and utimes Functions

本文介绍了futimens和utimensat两个系统调用,用于精确到纳秒级别改变文件的访问时间和修改时间。同时展示了如何使用这些函数保持文件的时间戳不变,并提供了一个具体的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一系列用于改变文件访问时间( access )和修改时间( modification )的系统调用

futimens, utimensat - change file timestamps with nanosecond precision

futimens, utimensat 提供纳秒尺寸,通过使用timespec结构体。

#include <fcntl.h> /* Definition of AT_* constants */
#include <sys/stat.h>

int futimens(int fd, const struct timespec times[2]);
int utimensat(int dirfd, const char *pathname,
                     const struct timespec times[2], int flags);
//Return: 0 if OK, -1 on error

结构体:timespec

struct timespec {
               time_t tv_sec;        /* seconds */
               long   tv_nsec;       /* nanoseconds */
};

futimens

times[0]存放的access time,times[1]存放modification time.这两个时间是日历时间(calendar time)。

timestamps(时间戳)可以用下面4种方法来指定:
1. times是NULL指针。这样timestamps被设置为当前时间。
2. timestimespec结构体数组。如果tv_nsec field为特殊值UTIME_NOW,相应的timestamp被设定为当前时间。相应的tv_secfield被忽略。
3. timestimespec结构体数组。如果tv_nsec field为特殊值UTIME_OMIT,相应的timestamp不改变。相应的tv_secfield被忽略。
4. timestimespec结构体数组。如果tv_nsec fieldUTIME_OMITUTIME_NOW以外的值,timestamp相应地被设置为tv_sectv_nsec field的值。

需要执行这些系统调用的权限由times 参数决定:

  • If times is a null pointer or if either tv_nsec field is set to UTIME_NOW, either the effective user ID of the process must equal the owner ID of the file, the process must have write permission for the file, or the process must be a superuser process.
  • If times is a non-null pointer and either tv_nsec field has a value other than UTIME_NOW or UTIME_OMIT, the effective user ID of the process must equal the owner ID of the file, or the process must be a superuser process. Merely having write permission for the file is not adequate(仅仅有文件的write权限是不够的).
  • If times is a non-null pointer and both tv_nsec fields are set to UTIME_OMIT, no permissions checks are performed.

With futimens, you need to open the file to change its times.

utimensat

The utimensat function provides a way to change a file’s times using the file’s name. The pathname argument is evaluated relative to the dirfd argument, which is either a file descriptor of an open directory or the special value AT_FDCWDto force evaluation relative to the current directory of the calling process. If pathname specifies an absolute pathname(绝对路径), then the dirfd argument is ignored.

The flag argument to utimensat can be used to further modify the default behavior. If the AT_SYMLINK_NOFOLLOW flag is set, then the times of the symbolic link itself are changed (if the pathname refers to a symbolic link). The default behavior is to follow a symbolic link and modify the times of the file to which the link refers.

Both futimens and utimensat are included in POSIX.1.(如上介绍到两种系统调用都是包含在POSIX1规范中的)

utime, utimes - change file last access and modification times

#include <sys/types.h>
#include <utime.h>
int utime(const char *filename, const struct utimbuf *times);

#include <sys/time.h>
int utimes(const char *filename, const struct timeval times[2]);
//Return 0 if OK, -1 on error

需要注意的是这两个函数修改的是秒和毫秒(ms)不是纳秒

struct timeval {
    time_t tv_sec;   /* seconds */
    long   tv_usec;  /* microseconds */
};

我们发现,changed-status timest_ctim—inode最后修改的时间,我们是无法指定其值的,该值会在调用utime的时候自动更新。

在一些Unix版本的命令中,touch使用了这些系统调用之一。此外tarcpio等标准archive存档程序中也使用了这些系统调用来设置文件时间。

Example

使用openO_TRUNC截断文件长度到0,但是不改变他们的access time或者modification time.为了达到这一目的,我们先用stat获取时间,然后截断文件,最后使用futimens来重置(reset)时间

#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main(int argc, char *argv[])
{
    int fd;
    struct stat timebuf;
    struct timespec times[2];
/*先确定命令行参数合法性*/
    if(argc != 2)
    {
        fprintf(stderr, "usage: a.out <file pathname>\n");
        exit(-1);
    }
/*获取文件截断前数据*/
    if(stat(argv[1], &timebuf) != 0)
    {
        fprintf(stderr, "stat error!\n");
        exit(-1);
    }
 /*用open截短文件*/
    if((fd = open(argv[1], O_TRUNC)) < 0)
    {
        fprintf(stderr, "open error: %s\n", strerror(errno));
        exit(-1);
    }
    times[0] = timebuf.st_atim;
    times[1] = timebuf.st_mtim;
/*设置文件时间与截断前一致*/
    if(futimens(fd, times) != 0)
    {
        fprintf(stderr, "futimens error: %s\n", strerror(errno));
        exit(-1);
    }

    close(fd);

    return 0;
}

验证:

$ls -l file
$./a.out file
$ls -l     `check time`
$ls -lu    `check last-access time`
$ls -lc    `check changed-status time`

你会发现last-modificationlast-access时间都没有改变,但是changed-status times已经被更改到程序运行的时间

<think>好的,用户的问题是关于在示例代码中用utime替换utimes的。我需要先理解这两个函数的区别和用途。utime和utimes都是用于修改文件的时间戳,但它们的参数和精度可能不同。 首先,utime函数在C语言中,原型是int utime(const char *filename, const struct utimbuf *times)。它允许设置文件的访问时间和修改时间,精确到秒。而utimes函数则是int utimes(const char *filename, const struct timeval times[2]),使用微秒级的精度,可以设置更精确的时间。 用户提到在示例代码中替换utime为utimes,我需要考虑参数的变化。utimbuf结构体有两个成员:actime和modtime,都是time_t类型。而utimes需要的是timeval数组,每个timeval包含秒和微秒。所以在替换时,需要调整参数的结构,可能需要将原来的秒数转换为timeval结构,并设置微秒部分为0。 另外,还需要注意函数返回值和错误处理。两个函数在成功时都返回0,失败时返回-1,并设置errno。因此,错误处理部分可能不需要改动,但需要确保参数传递正确。 还需要检查包含的头文件是否正确。utime可能需要#include <utime.h>,而utimes可能需要#include <sys/time.h>。替换函数后,头文件也需要相应调整。 另外,考虑到兼容性问题,utime是POSIX标准的一部分,而utimes可能在某些系统中有不同的支持情况。需要确认目标平台是否支持utimes函数,避免替换后出现兼容性问题。 最后,需要提醒用户在实际替换时,检查示例代码中时间参数的构造方式,确保使用正确的结构体和时间单位。可能需要进行类型转换,比如将原来的time_t转换为timeval的tv_sec字段,并设置tv_usec为0。 总结一下,替换步骤包括:修改函数名,调整参数结构,处理时间精度的转换,更新头文件,检查兼容性。同时,提供一个修改后的代码示例会有帮助,让用户更清楚如何操作。</think>在系统编程中,`utime`和`utimes`都是用于修改文件时间戳的函数,但它们在精度和参数结构上有所不同。以下是两者的对比及替换方法: --- ### 一、核心区别对比表 | 特性 | utime | utimes | |---------------------|---------------------------------|---------------------------------| | **时间精度** | 秒级 | 微秒级 | | **参数结构** | `struct utimbuf` | `struct timeval[2]` | | **头文件** | `<utime.h>` | `<sys/time.h>` | | **原型** | `int utime(path, &utimbuf)` | `int utimes(path, timeval*)` | | **访问/修改时间设置** | `actime`和`modtime` | `tv[0]`(访问时间), `tv[1]`(修改时间) | --- ### 二、替换步骤 #### 1. 参数结构调整 原`utime`代码示例: ```c #include <utime.h> struct utimbuf new_times; new_times.actime = 1622500000; // 访问时间 new_times.modtime = 1622500000; // 修改时间 utime("test.txt", &new_times); ``` 替换为`utimes`的代码: ```c #include <sys/time.h> struct timeval new_times[2]; new_times[0].tv_sec = 1622500000; // 访问时间 (秒) new_times[0].tv_usec = 0; // 微秒部分 (0表示不设置) new_times[1].tv_sec = 1622500000; // 修改时间 (秒) new_times[1].tv_usec = 0; utimes("test.txt", new_times); ``` --- #### 2. 精度扩展示例 如果需要设置微秒级时间: ```c struct timeval precise_times[2]; precise_times[0].tv_sec = 1622500000; precise_times[0].tv_usec = 500000; // 500毫秒 precise_times[1].tv_sec = 1622500000; precise_times[1].tv_usec = 123456; utimes("file.txt", precise_times); ``` --- ### 三、关键注意事项 1. **兼容性问题**: - 某些嵌入式系统可能不支持`utimes` - 可通过宏定义实现兼容: ```c #ifndef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 200809L #endif ``` 2. **时间获取方式**: - 建议使用`gettimeofday()`获取当前精确时间: ```c struct timeval curr_time; gettimeofday(&curr_time, NULL); ``` 3. **错误处理**: ```c if (utimes("file.txt", new_times) == -1) { perror("utimes failed"); switch(errno) { case EACCES: printf("权限不足\n"); break; case ENOENT: printf("文件不存在\n"); break; } } ``` --- ### 四、进阶用法 通过`futimes`修改已打开文件的时间戳: ```c FILE *fp = fopen("data.log", "r+"); if (fp) { struct timeval f_times[2]; // ... 设置时间 ... futimes(fileno(fp), f_times); // 使用文件描述符 fclose(fp); } ``` 这种替换不仅提升了时间精度,还能更好地与现代文件系统配合使用。实际项目中建议优先使用`utimes`,除非需要兼容旧系统。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猎羽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值