3

I am using Delphi 2010 and looking for a way to use CreateFile Windows API function to append data rather than overwriting it in the specified file?

I am not looking for an optional way to do it such as Append() or Rewrite() or similar. I am looking specifically to do this by use of CreateFile Windows API function.

I tried using:

// this will open existing file but will **overwrite** data in the file.
fHandle:= CreateFile(PChar(FName), GENERIC_READ or GENERIC_WRITE, 0, 
      nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); 

// this will recreate file each time therefore deleting its original content
fHandle:= CreateFile(PChar(FName), GENERIC_READ or GENERIC_WRITE, 0, 
      nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); 

Much appreciated,

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
d.b
  • 95
  • 2
  • 9
  • 2
    Why not [`TFileStream`](http://docwiki.embarcadero.com/VCL/2010/en/Classes.TFileStream)? It is an easy to use wrapper of that API. Or use `CreateFile` and [`THandleStream`](http://docwiki.embarcadero.com/VCL/2010/en/Classes.THandleStream) – Sir Rufo Apr 15 '14 at 21:58

2 Answers2

3

I suspect that OPEN_ALWAYS is actually what you need here.

Opens a file, always. If the specified file exists, the function succeeds and the last-error code is set to ERROR_ALREADY_EXISTS (183).

If the specified file does not exist and is a valid path to a writable location, the function creates a file and the last-error code is set to zero.

And if you are writing then you can remove GENERIC_READ.

Another problem that I anticipate is that when the file is opened, the file position is set to the beginning of the file. Seek to the end to deal with that.

Win32Check(SetFilePointerEx(fHandle, 0, nil, FILE_END));

Alternatively you can use FILE_APPEND_DATA instead of GENERIC_WRITE.

Handle:= CreateFile(PChar(Name), FILE_APPEND_DATA, 0, 
  nil, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); 

When you use FILE_APPEND_DATA, providing that you do not also use FILE_WRITE_DATA, all writes are made to the end of the file, irrespective of the current value of the file pointer.

The documentation says it like this:

For a file object, the right to append data to the file. (For local files, write operations will not overwrite existing data if this flag is specified without FILE_WRITE_DATA.)

Note that older versions of Delphi do not define FILE_APPEND_DATA and so you need to:

const
  FILE_APPEND_DATA = $0004;   

All this said, I suspect that, a stream or a writer class is a better option here. Are you sure you want to get down and dirty with the Win32 API?

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • 3
    You can optionally specify `FILE_APPEND_DATA` without `FILE_WRITE_DATA` in the `dwDesiredAccess` parameter of `CreateFile()`, and it will automatically write data to the end of the file without you having to seek to the end of the file manually. – Remy Lebeau Apr 15 '14 at 22:46
  • @RemyLebeau Hi REmy and thanks for your reply. I am not sure if I am missing somethign, but I already tried using FILE_APPEND_DATA and it is saying that FILE_APPEND_DATA is undeclared. I am using Delphi 2010. Here is what I do: fHandle := CreateFile(PChar(FName), FILE_APPEND_DATA, 0, nil, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); – d.b Apr 15 '14 at 23:16
  • @d.b: `FILE_APPEND_DATA` was added to the `Windows` unit in XE. – Remy Lebeau Apr 16 '14 at 00:00
1

Specify that you want File_Append_Data access in the second parameter without also requesting File_Write_Data access. Then all writes will be at the end of the file.

To open a file, creating it if it doesn't already exist, pass Open_Always for the dwCreationDisposition parameter. (There are only five possible values documented for that parameter, so it doesn't take long to look down the list and select the one that most closely matches your needs.)

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
  • Hi Rob and thanks for your reply. I am not sure if I am missing somethign, but I already tried using FILE_APPEND_DATA and it is saying that FILE_APPEND_DATA is undeclared. I am using Delphi 2010. Here is what I do: fHandle := CreateFile(PChar(FName), FILE_APPEND_DATA, 0, nil, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); – d.b Apr 15 '14 at 23:17
  • You can declare it yourself. Its value is 4. – Rob Kennedy Apr 15 '14 at 23:38