3

The only way I found to get a file size is to use the GetFileSizeEx() function. However, this function requires a HANDLE to the file, and if the file is already open for exclusive access I will not be able to get a HANDLE for it and hence I will not be able to get its size.

So is there a way to get a file size even if it is already open for exclusive access?

Thomas Dickey
  • 51,086
  • 7
  • 70
  • 105
John
  • 1,049
  • 1
  • 14
  • 34

1 Answers1

3

Edit, (see comments)
Using GetFileInformationByHandle

ULONGLONG filesize = 0; 
HANDLE h = CreateFile(filename, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, 
    NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 
if (h != INVALID_HANDLE_VALUE)
{ 
    BY_HANDLE_FILE_INFORMATION info;
    memset(&info, 0, sizeof(BY_HANDLE_FILE_INFORMATION));
    if (GetFileInformationByHandle(h, &info)) 
    { 
        ULARGE_INTEGER ul = { 0 };
        ul.LowPart = info.nFileSizeLow; 
        ul.HighPart = info.nFileSizeHigh;
        filesize = ul.QuadPart; 
    } 
    CloseHandle(h); 
} 

Another method, see GetFileAttributesEx


There is also FindFirstFile, but this can be inaccurate

From MSDN documentation for FindFirstFile

Note In rare cases or on a heavily loaded system, file attribute information on NTFS file systems may not be current at the time this function is called. To be assured of getting the current NTFS file system file attributes, call the GetFileInformationByHandle function.

Using FindFirstFile

WIN32_FIND_DATA ffd;
HANDLE hfind = FindFirstFile(filename, &ffd);
if (hfind != INVALID_HANDLE_VALUE)
{
    DWORD filesize = ffd.nFileSizeLow;

    //for files larger than 4GB:
    ULARGE_INTEGER ul;
    ul.LowPart = ffd.nFileSizeLow;
    ul.HighPart = ffd.nFileSizeHigh;
    ULONGLONG llfilesize = ul.QuadPart;

    FindClose(hfind);
}
Community
  • 1
  • 1
Barmak Shemirani
  • 30,904
  • 6
  • 40
  • 77
  • 2
    Alternatively, a call to [GetFileInformationByHandle](https://msdn.microsoft.com/en-us/library/windows/desktop/aa364952.aspx) can be used as well, if the file handle will be used for other operations later on. The file handle can be opened passing `0x0` as the *dwDesiredAccess* parameter to [CreateFile](https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858.aspx). – IInspectable Nov 16 '15 at 11:52
  • @IInspectable `GetFileInformationByHandle` looks better for this task, I edited the answer. – Barmak Shemirani Nov 16 '15 at 18:35
  • I don't think the latter solution will work as posted - you need to set the share mode to `FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE` rather than 0. When opening a file, the requested access has to be compatible with the share modes of any existing handles, *and* the share mode has to be compatible with the access granted to existing handles. – Harry Johnston Nov 17 '15 at 00:02
  • @HarryJohnston `FILE_SHARE_READ/FILE_SHARE_WRITE` affect the subsequent calls to `CreateFile` (while the handle is still open). In this case there is no request for read/write/delete, therefore share flags should be irralevent. If I don't have read/write access then I have no say in share flags either. I am only guessing though, the zero flag for `dwDesiredAccess` is not well documented. – Barmak Shemirani Nov 17 '15 at 01:10
  • 1
    *FILE_SHARE_READ/FILE_SHARE_WRITE affect the subsequent calls to CreateFile* - a common misunderstanding. The share flags you specify *must* be compatible with any existing handles, or your call to CreateFile will fail. – Harry Johnston Nov 17 '15 at 01:33
  • `FindFirstFile` is wrong anyway, I just found a note in documentation (see update). In OP's question, the original handle is opened in exclusive mode, in other cases the handle is opened in a different mode. The second handle is opened with zero access rights, I don't think share mode should be relevant to `GetFileInformationByHandle` – Barmak Shemirani Nov 17 '15 at 02:31
  • @BarmakShemirani: Share mode isn't relevant to `GetFileInformationByHandle` -- it's relevant to having your `CreateFile` call fail, then you can't call `GetFileInformationByHandle`. You cannot gain exclusive access to a file that someone else already has non-trivial access to. – Ben Voigt Nov 17 '15 at 02:48
  • @BenVoigt I am not attempting to gain exclusive access. I get the handle with access rights = zero, that means I have no read/write access. `CreateFile` doesn't fail and `GetFileInformationByHandle` doesn't fail. The OP has a file handle opened with exclusive access, that's another issue. – Barmak Shemirani Nov 17 '15 at 03:36
  • @BenVoigt Okay, I think I finally get what you two are saying. It's an error and probably the system is forgiving me for making the error. I changed it. – Barmak Shemirani Nov 17 '15 at 04:11
  • @BenVoigt and HarryJohnson, I am still confused about this. If the file originally had exclusive access and I request `FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE` then I have somehow changed the access. I didn't think that's possible. I tested this in an older system and there are random crashes, but I don't know for sure what's the cause. And I can't put zero because that would supposedly requests exclusive access. – Barmak Shemirani Nov 17 '15 at 06:47
  • Using your code: `HANDLE h = CreateFile(filename, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);`, I was able to open a file even if it has already been opened for exclusive access, and I have attempted to call `GetFileSizeEx()` on the returned file handle and it worked. So why should I use `GetFileInformationByHandle()` instead of `GetFileSizeEx()`? *Note: This is the code I used to open the file with exclusive access: `HANDLE hFile = CreateFile(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);`* – John Nov 17 '15 at 12:48
  • John, If the other file handle adds a single byte to the file, and `FindNextFile` method is called immediately (or after a few clock cycles), then `FindNextFile` shows the old file size. Whereas `GetFileInformationByHandle` will show the new size immediately. By the way I tested it again on an old computer and it was okay, I had an unrelated problem before. – Barmak Shemirani Nov 17 '15 at 17:01
  • @John, it doesn't matter whether you use GetFileInformationByHandle or GetFileSizeEx, that's just a matter of taste. – Harry Johnston Nov 18 '15 at 01:18
  • @BenVoigt, having just tried it out I found that the call with zero access rights *does* work despite the sharing mode. I can only assume that's treated as an undocumented special case, i.e., the sharing mode is being ignored. – Harry Johnston Nov 18 '15 at 01:21
  • 1
    @BarmakShemirani, you aren't changing the access. If there are multiple handles to a file, the effective sharing mode for the file is the logical AND of the sharing mode for each of the handles. For example, if you specified only FILE_SHARE_WRITE and the original handle specified only FILE_SHARE_READ, the new effective sharing mode would be 0. If you specify all 1's, i.e., `FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE` then the effective sharing mode won't change. – Harry Johnston Nov 18 '15 at 01:31
  • @Barmak Shemirani I was talking about `GetFileSizeEx()` and not `FindNextFile()` (did you mean `FindFirstFile()`? ). Anyway, if the file has been closed, will `FindFirstFile()` return an older size? – John Nov 18 '15 at 09:15
  • Oh, I misread your comment. Yes `GetFileSizeEx` should work too (giving accurate size) as long as you open the handle with `zero` desiredAccess. I guess that would have been the simple solution. I meant `FindFirstFile` may give stale information. – Barmak Shemirani Nov 18 '15 at 14:10