4

I would like to create a file of arbitrary size using the Windows C/C++ API. I am using Windows XP service pack 2 with a 32 bit virtual address memory space. I am familiar with CreateFile.

However CreateFile does not have a size arument, The reason I want to pass in a size argument is to allow me to create memory mapping files which allow the user to access data structures of predetermined size. Could you please advise of the proper Windows C/C++ API function which allow me to create a file of arbritrary predetermined size? Thank you

MPelletier
  • 16,256
  • 15
  • 86
  • 137
Frank
  • 1,406
  • 2
  • 16
  • 42
  • What do you want to be in this file? Have you tried `SetEndOfFile` (http://msdn.microsoft.com/en-us/library/aa365531(v=VS.85).aspx)? – David Heffernan Jan 20 '11 at 20:54
  • David Heffernan, Thank you for your reply. If I understand your comment, I should first use SetFilePointer to move the file pointer to the desired physical size. Then , I should use SetEndOfFile to set the physical size for the specified file to the current position of the file pointer. I will try your suggestion right now, I want this file to contain data structures such as array of strings or structs. By the way, how I would do this in Linux/Unix? Thank you. – Frank Jan 20 '11 at 21:22

5 Answers5

8

You CreateFile as usual, SetFilePointerEx to the desired size and then call SetEndOfFile.

Yakov Galka
  • 70,775
  • 16
  • 139
  • 220
  • ybungalobill, Thank you for the answer. Do you know how I would do this Linux/Unix? Thank you for your help. – Frank Jan 20 '11 at 21:27
2

You don't need a file, you can use the pagefile as the backing for your memory mapped file, from the MSDN CreateFileMapping function page:

If hFile is INVALID_HANDLE_VALUE, the calling process must also specify a size for the file mapping object in the dwMaximumSizeHigh and dwMaximumSizeLow parameters. In this scenario, CreateFileMapping creates a file mapping object of a specified size that is backed by the system paging file instead of by a file in the file system.

You can still share the mapping object by use of DuplicateHandle.

wich
  • 16,709
  • 6
  • 47
  • 72
  • wich, Thank you for the answer. Do you how I could adapt your solution to Linux/Unix? Thank you for your help. – Frank Jan 20 '11 at 21:29
  • @Frank yes you can, pass file descriptor -1 and flag `MAP_ANON` to mmap – wich Jan 20 '11 at 21:46
  • wich, I am getting an ErrorCode of 1006 after I call CreateFileMapping. Here are the steps: 1. hFile=::CreateFile(FileName_,AccessMode_,ShareMode_,... This is OK. 2.LARGE_INTEGER largeint; largeint.u.LowPart = FileSize_; SetFilePointerEx(hFile,largeint,NULL,FileBegin); – Frank Jan 21 '11 at 01:11
  • wich, I am getting an ErrorCode of 1006 after I call CreateFileMapping. Here are the steps: 1. hFile=::CreateFile("test.mmap",AccessMode_,ShareMode_,... This is OK. 2.LARGE_INTEGER largeint; largeint.u.LowPart = FileSize_; SetFilePointerEx(hFile,largeint,NULL,FileBegin); 3. SetEndOfFile(hFile); 4. hMapping=::CreateFileMapping(hFile,(SECURITY_ATTRIBUTES *)Security_,PAGE_READWRITE,0,0,0); 5. Now GetLastError says I am getting a error code 1006. Could you please tell me how to fix this problem. We don't want to use the system paging file so we use the file "test.mmap" Thank you. – Frank Jan 21 '11 at 01:19
  • wich, I solved the problem with Error 1006 after I call CreateFileMapping. I subsituted SetFilePointer for SetFilePointerEx and now everything works. Now , I have to see if I can make mmap work on Linux and Solaris/IBM AIX Unix. Thank you for your help. – Frank Jan 21 '11 at 02:03
2

To do this on UNIX, seek to (RequiredFileSize - 1) and then write a byte. The value of the byte can be anything, but zero is the obvious choice.

brewbuck
  • 887
  • 6
  • 9
  • brewbuck, Thank you for your help. I followed your suggestion and I can doi this on Centos Lnux now, – Frank Jan 21 '11 at 10:36
1

according to your comments, you actually need cross-platform solution, so check Boost Interprocess library. it provides cross-platform shared memory facilities and more

Andriy Tylychko
  • 15,967
  • 6
  • 64
  • 112
  • Andy T. I have used Boost before and I like it. I used the Boost Regex library. However, on this project, we cannot use Boost because the Boost requires that all the Unix(Solaris, IBM AIX, HP) compiler use the latest release of their compilers. You can imagine the cost associated with acquiring the latest licenses from Solaris , IBM and HP. Thank you for your help – Frank Jan 21 '11 at 14:54
0

to do this on Linux, you can do the following:

/**
 *  Clear the umask permissions so we 
 *  have full control of the file creation (see man umask on Linux)
 */
mode_t origMask = umask(0);

int fd = open("/tmp/file_name",
      O_RDWR, 00666);

umask(origMask);
if (fd < 0)
{
  perror("open fd failed");
  return;
}


if (ftruncate(fd, size) == 0)
{
   int result = lseek(data->shmmStatsDataFd, size - 1, SEEK_SET);
   if (result == -1)
   {
     perror("lseek fd failed");
     close(fd);
     return ;
   }

   /* Something needs to be written at the end of the file to
    * have the file actually have the new size.
    * Just writing an empty string at the current file position will do.
    *newDataSize
    * Note:
    *  - The current position in the file is at the end of the stretched
    *    file due to the call to lseek().
    *  - An empty string is actually a single '\0' character, so a zero-byte
    *    will be written at the last byte of the file.
    */
   result = data->write(fd, "", 1);
   if (result != 1)
   {
     perror("write fd failed");
     close(fd);

     return;
   }
}
Leo
  • 1,160
  • 18
  • 31