Avoid updating last-accessed date/time when reading a file
Asked Answered
E

4

5

We're building a Windows-based application that traverses a directory structure recursively, looking for files that meet certain criteria and then doing some processing on them. In order to decide whether or not to process a particular file, we have to open that file and read some of its contents.

This approach seems great in principle, but some customers testing an early version of the application have reported that it's changing the last-accessed time of large numbers of their files (not surprisingly, as it is in fact accessing the files). This is a problem for these customers because they have archive policies based on the last-accessed times of files (e.g. they archive files that have not been accessed in the past 12 months). Because our application is scheduled to run more frequently than the archive "window", we're effectively preventing any of these files from ever being archived.

We tried adding some code to save each file's last-accessed time before reading it, then write it back afterwards (hideous, I know) but that caused problems for another customer who was doing incremental backups based on a file system transaction log. Our explicit setting of the last-accessed time on files was causing those files to be included in every incremental backup, even though they hadn't actually changed.

So here's the question: is there any way whatsoever in a Windows environment that we can read a file without the last-accessed time being updated?

Thanks in advance!

EDIT: Despite the "ntfs" tag, we actually can't rely on the filesystem being NTFS. Many of our customers run our application over a network, so it could be just about anything on the other end.

Eratosthenes answered 14/4, 2011 at 13:11 Comment(0)
S
6

The documentation indicates you can do this, though I've never tried it myself.

To preserve the existing last access time for a file even after accessing a file, call SetFileTime immediately after opening the file handle with this parameter's FILETIME structure members initialized to 0xFFFFFFFF.

Sidedress answered 14/4, 2011 at 13:26 Comment(3)
I can't believe I missed that! We're actually using a third-party library (no source code) to access the files, so we might not actually be able to do this, but it looks extremely promising. Experimentation time!Eratosthenes
This hasn't 100% solved my problem, but I'm accepting it as it's likely to be the best answer for most people asking the same question.Eratosthenes
Has anybody noticed any discrepancies with how the disablelastaccess is set and the 0xffffffff trick with regards to remote UNC files? I am seeing odd behavior where this documented procedure does not seem to work as expected.Phoenician
S
4

From Vista onwards NTFS does not update the last access time by default. To enable this see http://technet.microsoft.com/en-us/library/cc959914.aspx

Starting NTFS transaction and rolling back is very bad, and the performance will be terrible.

You can also do

FSUTIL behavior set disablelastaccess 0

Stonyhearted answered 27/4, 2011 at 1:58 Comment(1)
Your first sentence is wrong, at least if you are basing it on the link. It says: "Determines whether NTFS updates the last-access timestamp on each directory when it lists the directories on an NTFS volume."Theology
O
1

I don't know what your client minimum requirements are, but have you tried NTFS Transactions? On the desktop the first OS to support it was Vista and on the server it was Windows Server 2008. But, it may be worth a look at.

Start an NTFS transaction, read your file, rollback the transaction. Simple! :-). I actually don't know if it will rollback the Last Access Date though. You will have to test it for yourself.

Here is a link to a MSDN Magazine article on NTFS transactions which includes other links. http://msdn.microsoft.com/en-us/magazine/cc163388.aspx

Hope it helps.

Olnek answered 14/4, 2011 at 13:27 Comment(4)
Interesting... we may be able to use that. I know I tagged this question "ntfs", but we can't guarantee that the filesystem is NTFS (it could be just about anything, including NFS, NetWare or something equally bizarre).Eratosthenes
Ah, yes, that is strictly a NTFS feature, no FAT32 either. Good luck and keep us posted. I also liked the idea from Luke using SetFileTime, but if you are using managed code (.NET), it would mean using a P/Invoke call as you can't pass "-1" as a DateTime in the managed code. P/Invoke SetFileTime. Assuming it's even doable with your 3rd party library.Olnek
OK, here's a thought (not knowing your product or full requirements). How about a blend of tech. If it was an NTFS customer that had the backup issue of backing up an unchanged file where you reset the last access date back after your reads, then try TxF (Transactional NTFS), otherwise don't. Now, you may or may not be able to tell what the underlying file system is, so it may have to be manually configured. Just a though.Olnek
Yep, I'm starting to think along the lines of a blended solution, with the crufty "rewrite the last accessed time" as a last resort. We're not using managed code for this part of the app (native C++) so that isn't a problem.Eratosthenes
G
-1

Also you can use the method File.GetLastAccessTime(fileInfoLocation); before the code that will change the LastAccessTime and then after the code thats going to change the LastAccessTime you can use the method File.SetLastAccessTime(fileInfoLocation, originalLastAccessTime); to set it back to what it was though you need Administrative privileges for the SetLastAccessTime part if you want to change it to the original AKA run as admin. Heres some code for example:

FileInfo fileInfoLocation = new FileInfo(getAllExeLocation[l]);
                                                DateTime originalLastAccessTime = File.GetLastAccessTime(fileInfoLocation.FullName);//Save the LastAccessTime before it was changed by Icon.Extract Method
                                                exeIcon = Icon.ExtractAssociatedIcon(fileInfoLocation.FullName);//This changes LastAccessTime
                                                File.SetLastAccessTime(fileInfoLocation.FullName, originalLastAccessTime);//Set the LastAccessTime to the originalOne though it needs Privileges to do this one(run as admin) or Use Try-Catch statement
Graziano answered 12/5 at 20:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.