Thursday 14 August 2014

Useless? Delphi IOUtils.pas

I am a computer programmer and my preferred programming tool is Delphi.

But I cannot get in terms with the newer versions of it - 2010, XE2, XE6 (the company I work for owns Delphi 3, 5, 7, 2007, 2010, XE2, XE6).

I have the feeling that part of the code provided is written to test the fellow programmer's skills and patience. It looks OK for a hobbyist jobs, but cannot be used for serious work. The main reason for this is the assumption of the coders that this code would run on God's computer - fast as a light, with ocean of RAM and very intelligent memory manager. The code supplied has to be changed (via class inheritance or helpers) in order to become usable according my requirements...

There are many such places in Delphi and today I am writing about IOUtils.pas

IOUtils.pas was introduced in Delphi 2010 - 7 Delphi versions ago. Initially I thought that it is very useful thing. But spending some time playing with it (Delphi 2010), I decided that it is useless and returned to the good old FindFirst/FindNext/FindClose. Tonight I decided to give it another chance. But I was bitterly disappointed again.
  • All functions return dynamic array of strings that contain just the file names. If you need more information (File Size for example) - you need to call other methods, passing the file name as parameter.
  • GetFiles methods that match pattern use MatchesMask function for each file name to be checked. The problem is that this function creates and destroys TMask object on each call. Creating TMask object once and using its Matches(filename) method made the program to run 50 times faster. And there is no way to check against several patterns.
  • There is no easy way to control and monitor the progress of many procedures and functions, if you need them to run in a separate thread. Example: TDirectory.GetFileSystemEntries. The only way to filter the file names returned is to use Predicate function, passed as parameter. Very powerful feature, because I can do all necessary checks (even against list of masks) and I can fill my data structure with all information I need - size, attributes and times. But in this case I do not need the dynamic array of file names returned. I can avoid it by setting the predicate to return false, but that is just work around... And this predicate cannot be used to report progress of a thread, because it cannot be called through Synchronize. And if there was a way - I would not like to Synchronize for each file...
There is TFile.Move function. But its name is misleading. It does not move the file (a direct call to windows API function MoveFile(source, destination)). It copies the file into the destination and then deletes the original. Why??? 

The reason I needed to move files was the side effect of the recent (12 August 2014) MS Windows 7 update (Thank you, MS!) - it is described here: Delphi 2007 cannot start, because EditorLineEnds.ttr is locked by System. Up to now the only way around the problem (if I want to keep the installed Windows updates) is to move the EditorLineEnds.ttr file out of AppData\Temp folder before Delphi 2007 starts. I wrote little utility that checks whether there is such file in AppData\Temp and if it is there - it moves it under a new name into different folder (adding sequential number to the file name). These files remain locked during the current Windows session even after moving/renaming them - if I reboot - I can delete them. The attempt to use TFile.Move copied the file into the new folder, but failed to delete the original, because it was locked by Windows...

At the end - I left IOUtils and implemented small (20 lines code, no threads used) tool that uses FindFirst/FindNext to find out the max number added already to the file name and MoveFile Windows API function to move the file into different folder under new name.

you can't teach an old dog new tricks

Disclaimer: All brand names and trademarks mentioned above belong to their owners. All facts are correct to my best knowledge on 14 August 2014. No attempt is made to advertise or anti advertise any company. All opinions are personal and do not involve anybody else except me.