修改文件目录时间的代码-touch
本帖最后由 go4399 于 2023-11-14 11:11 编辑使用与linux下touch一致,部分功能没有实现。支持命令行下通配符,如touch \*.\*
```cpp
// touch.c
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
int _dowildcard = 1; // 1 = support wildcard, 0 = not
#define CH_ATIME 1
#define CH_MTIME 2
#define CH_CTIME 4
#define TM_SET 8
static int change_times = 0;
static FILETIME atime;
static FILETIME ctime;
static FILETIME mtime;
void usage()
{
fputws(L"Usage: touch ... FILE...\n", stdout);
fputws(L"Update the access and modification times of each FILE to the current time.\n\n\
Mandatory arguments to long options are mandatory for short options too.\n\
-a change only the access time\n\
-c change only the creation time\n\
-m change only the modification time\n\
-r FILE use this file's times instead of current time\n\
-t STAMP use [YY]MMDDhhmm[.ss] instead of current time\n", stdout);
}
int use_reference(const wchar_t* fileName)
{
HANDLE hFile;
if (change_times & TM_SET)
{
return 0;
}
hFile = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
if (GetFileTime(hFile, &ctime, &atime, &mtime))
{
change_times |= TM_SET;
}
CloseHandle(hFile);
}
return change_times & TM_SET;
}
int use_stamp(wchar_t* opt)
{
wchar_t* p;
SYSTEMTIME st;
if (change_times & TM_SET)
{
return 0;
}
GetLocalTime(&st);
st.wMilliseconds = 0;
p = wcschr(opt, L'.');
if (p)
{
if (p == 0)
{
st.wSecond = _wtoi(p + 1);
*p = 0;
}
else
{
return 0;
}
}
else
{
st.wSecond = 0;
p = opt + wcslen(opt);
}
if (p >= opt + 2)
{
p -= 2;
st.wMinute = _wtoi(p);
*p = 0;
if (p >= opt + 2)
{
p -= 2;
st.wHour = _wtoi(p);
*p = 0;
if (p >= opt + 2)
{
p -= 2;
st.wDay = _wtoi(p);
*p = 0;
if (p >= opt + 2)
{
p -= 2;
st.wMonth = _wtoi(p);
*p = 0;
if (p == opt)
{
}
else if (p == opt + 2)
{
p -= 2;
st.wYear = (st.wYear / 100) * 100 + _wtoi(p);
}
else if (p == opt + 4)
{
p -= 4;
st.wYear = _wtoi(p);
}
else
{
return 0;
}
if (SystemTimeToFileTime(&st, &ctime) && LocalFileTimeToFileTime(&ctime, &atime))
{
ctime = atime;
mtime = atime;
change_times |= TM_SET;
}
}
}
}
}
return change_times & TM_SET;
}
int use_current()
{
SYSTEMTIME st;
if (change_times & TM_SET)
{
return 0;
}
GetSystemTime(&st);
st.wMilliseconds = 0;
if (SystemTimeToFileTime(&st, &atime))
{
ctime = atime;
mtime = atime;
change_times |= TM_SET;
}
return change_times & TM_SET;
}
int touch(const wchar_t* fileName)
{
int ret = 0;
HANDLE hFile = CreateFileW(fileName, FILE_WRITE_ATTRIBUTES, 0, 0, OPEN_EXISTING, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
if (SetFileTime(hFile, change_times & CH_CTIME ? &ctime : 0, change_times & CH_ATIME ? &atime : 0, change_times & CH_MTIME ? &mtime : 0))
{
ret = 1;
}
CloseHandle(hFile);
}
return ret;
}
int wmain(int argc, wchar_t **argv)
{
int ret = 1;
int i;
wchar_t* opt = 0;
for (i = 1; i < argc; ++i)
{
opt = argv;
if (opt == L'-')
{
if (opt != 0 && opt == 0)
{
if (opt == L'a')
{
change_times |= CH_ATIME;
}
else if (opt == L'c')
{
change_times |= CH_CTIME;
}
else if (opt == L'm')
{
change_times |= CH_MTIME;
}
else if (opt == L'r')
{
i++;
if (i < argc)
{
if (!use_reference(argv))
{
i = argc;
break;
}
}
}
else if (opt == L't')
{
i++;
if (i < argc)
{
if (!use_stamp(argv))
{
i = argc;
break;
}
}
}
else
{
i = argc;
break;
}
}
else
{
i = argc;
break;
}
}
else
{
break;
}
}
if (i == argc)
{
usage();
return 0;
}
if (!(change_times & (CH_ATIME | CH_CTIME | CH_MTIME)))
{
change_times |= CH_ATIME | CH_CTIME | CH_MTIME;
}
use_current();
for (; i < argc; ++i)
{
ret &= touch(argv);
}
return ret;
}
``` 感谢分享。
UnxUtils for Windows 命令行工具包里面有一个 touch.exe 可以实现类似 Linux 里面的效果:
https://unxutils.sourceforge.net/
C:\Test\>touch --help
Usage: touch ... FILE...
Update the access and modification times of each FILE to the current time.
-a change only the access time
-c do not create any files
-d, --date=STRING parse STRING and use it instead of current time
-f (ignored)
-m change only the modification time
-r, --reference=FILE use this file's times instead of current time
-t STAMP use MMDDhhmm[YY][.ss] instead of current time
--time=WORD access -a, atime -a, mtime -m, modify -m, use -a
--help display this help and exit
--version output version information and exit
STAMP may be used without -t if none of -drt, nor --, are used.
C:\Test\>touch --version
touch (GNU fileutils) 3.16
C:\Test\>dir 1.txt | findstr "1.txt"
2023/11/1119:36 207 1.txt
C:\Test\>touch 1.txt
C:\Test\>dir 1.txt | findstr "1.txt"
2023/11/1414:50 207 1.txt
CoreUtils for Windows 命令行工具包里面有一个 touch.exe 可以实现类似 Linux 里面的效果:
https://gnuwin32.sourceforge.net/packages/coreutils.htm
C:\Test\>touch --version
touch (GNU coreutils) 5.3.0
是开源的,可以下载它的C源代码。 参考了https://ftp.gnu.org/gnu/coreutils/coreutils-9.4.tar.xz这个版本.
目的是能被win下的tinycc编译,通配符不支持UCRT 大致看了一下。有如下问题:
1. 参数解析过于复杂了。建议优化。
2. 没有注释。
3. 函数中没有换行。分开的功能,加以添加上换行,提高可读性。
4. touch 函数逻辑有点小问题:
在CreateFileW失败的时候,返回0。0应该是代表成功。
5. 参数判断应该在参数解析之前。
dudupangle 发表于 2023-11-15 09:10
大致看了一下。有如下问题:
1. 参数解析过于复杂了。建议优化。
2. 没有注释。
4. https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew
CreateFileW Return value:
If the function succeeds, the return value is an open handle to the specified file, device, named pipe, or mail slot.
If the function fails, the return value is INVALID_HANDLE_VALUE. To get extended error information, call GetLastError.
返回0的情况,没有说明。 go4399 发表于 2023-11-15 09:33
4. https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew
CreateFileW ...
我的意思是你写的touch函数返回值的含义是什么。0成功,小于0失败?你现在的逻辑是如果CreateFileW失败,返回ret。ret的初值为0。我认为这个和你的设计不相符。 本帖最后由 go4399 于 2023-11-15 14:24 编辑
dudupangle 发表于 2023-11-15 11:58
我的意思是你写的touch函数返回值的含义是什么。0成功,小于0失败?你现在的逻辑是如果CreateFileW失败, ...
touch函数,1表示成功,0表示失败
这个逻辑和原始coreutils版本一致 有个小建议:1.可以多写写注释,方便别人理解,更方便自己理解,要不等过段时间就忘了自己的想法了
我之前也写过这种,没几天就忘了很多具体的细节
页:
[1]