What are in this Module?
My Training Period: yy hours. Before you begin, read someinstruction here.
Abilities that supposed to be acquired:
Setting and Getting the Timestamp of a File
|
Not all file systems can record creation and last access time and not all file systems record them in the same manner. For example, on Windows NT FAT, create time has a resolution of 10 milliseconds, write time has a resolution of 2 seconds, and access time has a resolution of 1 day (really, the access date). On NTFS, access time has a resolution of 1 hour.
Therefore, the GetFileTime() function may not return the same file time information set using theSetFileTime() function. Furthermore, FAT records times on disk in local time.
However, NTFS records times on disk in UTC, so it is not affected by changes in time zone or daylight saving time.
The following example demonstrates how to extract the timestamp of a file. It will show the date and time when the file is created, last accessed and last written.
Functions used in this program are CreateFile(), GetFileType(), GetFileSize(), GetFileTime(),FileTimeToSystemTime(), SystemTimeToTzSpecificLocalTime() and CloseHandle().
#include <windows.h>
#include <stdio.h>
int main()
{
// a file handle
HANDLE hFile1;
FILETIME ftCreate, ftAccess, ftWrite;
SYSTEMTIME stUTC, stLocal, stUTC1, stLocal1, stUTC2, stLocal2;
// a filename, change accordingly
char fname1[ ] = "c:\\testfile.txt";
// temporary storage for file sizes
DWORD dwFileSize;
DWORD dwFileType;
// opening the existing file
hFile1 = CreateFile(fname1, // file to open
GENERIC_READ, // open for reading
FILE_SHARE_READ, // share for reading
NULL, // default security
OPEN_EXISTING, // existing file only
FILE_ATTRIBUTE_NORMAL, // normal file
NULL); // no attribute template
if(hFile1 == INVALID_HANDLE_VALUE)
{
printf("Could not open %s file, error %d\n", fname1, GetLastError());
return 4;
}
dwFileType = GetFileType(hFile1);
dwFileSize = GetFileSize(hFile1, NULL);
printf("%s size is %d bytes and file type is %d\n", fname1, dwFileSize, dwFileType);
// retrieve the file times for the file.
if(!GetFileTime(hFile1, &ftCreate, &ftAccess, &ftWrite))
{
printf("Something wrong lol!\n");
return FALSE;
}
// convert the created time to local time.
FileTimeToSystemTime(&ftCreate, &stUTC);
SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal);
// convert the last-access time to local time.
FileTimeToSystemTime(&ftAccess, &stUTC1);
SystemTimeToTzSpecificLocalTime(NULL, &stUTC1, &stLocal1);
// convert the last-write time to local time.
FileTimeToSystemTime(&ftWrite, &stUTC2);
SystemTimeToTzSpecificLocalTime(NULL, &stUTC2, &stLocal2);
// build a string showing the date and time.
printf("Created on: %02d/%02d/%d %02d:%02d\n", stLocal.wDay, stLocal.wMonth, stLocal.wYear, stLocal.wHour, stLocal.wMinute);
printf("Last accessed: %02d/%02d/%d %02d:%02d\n", stLocal1.wDay, stLocal1.wMonth, stLocal1.wYear, stLocal1.wHour, stLocal1.wMinute);
printf("Last written: %02d/%02d/%d %02d:%02d\n", stLocal2.wDay, stLocal2.wMonth, stLocal2.wYear, stLocal2.wHour, stLocal2.wMinute);
// close the file's handle and itself
CloseHandle(hFile1);
return 0;
}
The output:
c:\testfile.txt size is 1289 bytes and file type is 1
Created on: 24/05/2005 22:33
Last accessed: 24/05/2005 22:40
Last written: 24/05/2005 22:37
Press any key to continue
---------------------------------------------Have a break------------------------------------------------
This part will try to explain how to access the structure elements. It is same as what you have learnt in C and C++.
We will use the previous program examples as our reference. First of all let get the information for theFileTimeToSystemTime() function.
This function converts a file time to system time format. The following is the prototype.
BOOL FileTimeToSystemTime( const FILETIME* lpFileTime, LPSYSTEMTIME lpSystemTime);
Parameter | Description |
lpFileTime | [in] Pointer to aFILETIME structure containing the file time to convert to system date and time format. This value must be less than0x8000000000000000. Otherwise, the function fails. |
lpSystemTime | [out] Pointer to aSYSTEMTIME structure to receive the converted file time. |
Table 2: FileTimeToSystemTime() parameters. |
If the function succeeds, the return value is nonzero.
If the function fails, the return value is zero. To get extended error information, call GetLastError().
In the previous program example we have used two structures, FILETIME and SYSTEMTIME. The following are the definition for both structures.
This structure is a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC). For 32 bits, we have to divide the 64 bits value into two parts, the low 32 bits and the high 32 bits.
typedef struct _FILETIME {DWORD dwLowDateTime;
DWORD dwHighDateTime;
} FILETIME,*PFILETIME;
Here we have synonym for struct _FILETIME (new shorter name should be FILETIME or *PFILETIME).
Member | Description |
dwLowDateTime | Low-order part of the file time. |
dwHighDateTime | High-order part of the file time. |
Table 3: _FILETIME structure member. |
This structure represents a date and time using individual members for the month, day, year, weekday, hour, minute, second, and millisecond.
typedef struct _SYSTEMTIME {WORD wYear;
WORD wMonth;
WORD wDayOfWeek;
WORD wDay;
WORD wHour;
WORD wMinute;
WORD wSecond;
WORD wMilliseconds;
} SYSTEMTIME, *PSYSTEMTIME;
Here we have created a synonym for struct _SYSTEMTIME (new shorter name should beSYSTEMTIME or *PSYSTEMTIME).
Member | Description |
wYear | The year. This value must be greater than 1601.For Windows Server 2003, Windows XP, this value cannot be greater than 30827. |
wMonth | The month; January = 1, February = 2, and so on. |
wDayOfWeek | The day of the week; Sunday = 0, Monday = 1, and so on. |
wDay | The day of the month. |
wHour | The hour. |
wMinute | The minute. |
wSecond | The second. |
wMilliseconds | The millisecond. |
Table 4: _SYSTEMTIME structure members. |
Then, let reconstruct the previous program example and scale down the codes to the structures application. Learn how the structure elements are accessed.
|
// opening the existing file
hFile1 = CreateFile(fname1, // file to open
GENERIC_READ, // open for reading
FILE_SHARE_READ, // share for reading
NULL, // default security
OPEN_EXISTING, // existing file only
FILE_ATTRIBUTE_NORMAL, // normal file
NULL); // no attribute template
if(hFile1 == INVALID_HANDLE_VALUE)
{
printf("Could not open %s file, error %ul\n", fname1, GetLastError());
return 4;
}
// retrieve created file times for the file.
if(!GetFileTime(hFile1, &ftCreate, NULL, NULL))
{
printf("Something wrong!\n");
return FALSE;
}
// viewing the unreadable...
// filing the 32 bit low part into variable low and another 32 bit high part into variable high
//Accessing the FILETIME structures' members, assigning them to some variables...
DWORD low = ftCreate.dwLowDateTime;
DWORD high = ftCreate.dwHighDateTime;
// trying to display the content in hex...
printf("Unreadable format...\n");
printf("32 bit low part = %0X and high = %0X\n", low, high);
// convert the file created time to local time.
FileTimeToSystemTime(&ftCreate, &stUTC);
SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal);
printf("\nReadable format...\n");
// build a readable string showing the date and time. Accessing the SYSTEMTIME structure's member
printf("UTC System Time\n");
printf("Created on: %02d/%02d/%d %02d:%02d\n", stUTC.wDay, stUTC.wMonth, stUTC.wYear, stUTC.wHour, stUTC.wMinute);
// accessing the SYSTEMTIME structures' members
printf("Local time\n");
printf("Created on: %02d/%02d/%d %02d:%02d\n", stLocal.wDay, stLocal.wMonth, stLocal.wYear, stLocal.wHour, stLocal.wMinute);
// close the file's handle and itself
CloseHandle(hFile1);
return 0;
}
The output:
Unreadable format...
32 bit low part = 97AFA6A0 and high = 1C5606D
Readable format...
UTC System Time
Created on: 24/05/2005 14:33
Local time
Created on: 24/05/2005 22:33
Press any key to continue
----------------------------------End on using structure in Win32 programming-----------------------------
The ReadFile() function checks for the end-of-file condition (eof) differently for synchronous (The synchronous reader uses only one thread) and asynchronous read operations (The asynchronous reader uses multiple threads for processing streams).
When a synchronous read operation reaches the end of a file, ReadFile() returns TRUE and sets the variable pointed to by lpNumberOfBytesRead to zero.
An asynchronous read operation can encounter the end of a file during the initiating call to ReadFile() or during subsequent asynchronous operation.
The following example test for the end of a file during a synchronous read operation.
// attempt a synchronous read operation
bResult = ReadFile(hFile, &inBuffer, nBytesToRead, &nBytesRead, NULL);
// check for eof
if(bResult && nBytesRead == 0)
{
// at the end of the file
}
The test for end-of-file during an asynchronous read operation is more difficult. There are three end-of-file indicators for asynchronous read operations:
ReadFile() returns FALSE and GetLastError() returns ERROR_HANDLE_EOF.
ReadFile() returns FALSE and GetLastError() returnsERROR_IO_PENDING.
GetOverlappedResult() returns FALSE and GetLastError() returnsERROR_HANDLE_EOF.
The following example shows how to test for an end-of-file during an asynchronous read operation:
// attempt to initiate an asynchronous read operation.
bResult = ReadFile(hFile, &inBuffer, nBytesToRead, &nBytesRead, NULL);
// check if there was a problem.
if(!bResult)
{
switch(dwError = GetLastError())
{
case ERROR_HANDLE_EOF:
// at the end of the file.
break;
case ERROR_IO_PENDING:
// I/O pending.
break;
}
}
// check on an asynchronous read operation.
bResult = GetOverlappedResult(hFile, &gOverlapped, &nBytesRead, TRUE);
// check if there was a problem.
if(!bResult)
{
switch(dwError = GetLastError())
{
case ERROR_HANDLE_EOF:
// at the end of the file
}
}
When an application calls CreateFile() to open a file for the first time, Windows places the file pointer at the beginning of the file. As bytes are read from or written to the file, Windows advances the file pointer the number of bytes read or written.
An application can position the file pointer to a specified offset by calling SetFilePointer().
The following Table lists the needed information in order to use the SetFilePointer() function.
Information | Description |
The function | SetFilePointer(). |
The use | Moves the file pointer of an open file. |
The prototype | DWORD SetFilePointer( HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod); |
Example | HANDLE hFile;
hFile = CreateFile(...); SetFilePointer( hFile,// must have GENERIC_READ and/or GENERIC_WRITE 0, // do not move pointer NULL, // hFile is not large enough to need thispointer FILE_CURRENT); // provides offset from current position |
The parameters | hFile - [in] Handle to the file whose file pointer is to be moved. The file handle must have been created with the GENERIC_READ or GENERIC_WRITE access right. lDistanceToMove - [in] Low-order 32 bits of a signed value that specifies the number of bytes to move the file pointer. IflpDistanceToMoveHigh is not NULL,lpDistanceToMoveHigh and lDistanceToMove form a single 64-bit signed value that specifies the distance to move. IflpDistanceToMoveHigh is NULL,lDistanceToMove is a 32-bit signed value. A positive value forlDistanceToMove moves the file pointer forward in the file, and a negative value moves the file pointer backward. lpDistanceToMoveHigh - [in] Pointer to the high-order 32 bits of the signed 64-bit distance to move. If you do not need the high-order 32 bits, this pointer must be set to NULL. When non-NULL, this parameter also receives the high-orderDWORD of the new value of the file pointer. dwMoveMethod - [in] Starting point for the file pointer move. This parameter can be one of the following values:
|
The return value | If theSetFilePointer() function succeeds andlpDistanceToMoveHigh is NULL, the return value is the low-orderDWORD of the new file pointer. IflpDistanceToMoveHigh is not NULL, the function returns the low orderDWORD of the new file pointer, and puts the high-orderDWORD of the new file pointer into theLONG pointed to by that parameter. If the function fails andlpDistanceToMoveHigh is NULL, the return value isINVALID_SET_FILE_POINTER. To get extended error information, callGetLastError(). If the function fails, andlpDistanceToMoveHigh is non-NULL, the return value isINVALID_SET_FILE_POINTER. However, becauseINVALID_SET_FILE_POINTER is a valid value for the low-orderDWORD of the new file pointer, you must checkGetLastError() to determine whether an error occurred. If an error occurred,GetLastError() returns a value other thanNO_ERROR. If the new file pointer would have been a negative value, the function fails, the file pointer is not moved, and the code returned byGetLastError() is ERROR_NEGATIVE_SEEK. |
The header file | <windows.h> |
Table 5: SetFilePointer() information. |
The SetFilePointer() function can also be used to query the current file pointer position by specifying a move method of FILE_CURRENT and a distance of zero, as shown in the following example.
#include <windows.h>
#include <stdio.h>
int main()
{
// handle for file
HANDLE hFile;
DWORD dwCurrentFilePosition;
// file and path, change accordingly to other file available on your machine for testing
char fname[20] = "c:\\module15.txt";
hFile = CreateFile(fname, // file to be opened
GENERIC_WRITE, // open for writing
FILE_SHARE_READ, // share for reading
NULL, // default security
OPEN_EXISTING, // open existing file
FILE_ATTRIBUTE_READONLY, // the file is read only
NULL); // no attribute template
if(hFile == INVALID_HANDLE_VALUE)
printf("Could not open %s file, error %d\n", fname, GetLastError());
printf("File's HANDLE is OK!\n");
dwCurrentFilePosition = SetFilePointer(
hFile, // must have GENERIC_READ and/or GENERIC_WRITE
0, // do not move pointer
NULL, // hFile is not large enough to need this pointer
FILE_CURRENT); //provides offset from current position
printf("Current file pointer position: %d\n", dwCurrentFilePosition);
dwCurrentFilePosition = SetFilePointer(
hFile, // must have GENERIC_READ and/or GENERIC_WRITE
10, // 10 bytes
NULL, // hFile is not large enough to need this pointer
FILE_CURRENT); // provides offset from current position
printf("Current file pointer position: %d\n", dwCurrentFilePosition);
return 0;
}
The output:
File's HANDLE is OK!
Current file pointer position: 0
Current file pointer position: 10
Press any key to continue
Further reading and digging:
Microsoft Visual C++, online MSDN.
ReactOS - Windows binary compatible OS - C/C++ source code repository, Doxygen.