{"id":1008,"date":"2008-02-11T23:12:08","date_gmt":"2008-02-11T13:12:08","guid":{"rendered":"http:\/\/www.flamingspork.com\/blog\/2008\/02\/11\/getting-a-file-size-on-windows\/"},"modified":"2008-02-11T23:12:08","modified_gmt":"2008-02-11T13:12:08","slug":"getting-a-file-size-on-windows","status":"publish","type":"post","link":"https:\/\/www.flamingspork.com\/blog\/2008\/02\/11\/getting-a-file-size-on-windows\/","title":{"rendered":"Getting a file size (on Windows)"},"content":{"rendered":"<p>The first point I&#8217;d like to make is that you&#8217;re using a Microsoft Windows API, so you have already lost. You are just not quite aware of how much you have lost.<\/p>\n<p>A quick look around and you say &#8220;Ahh&#8230; GetFileSize, that&#8217;s what I want to do!&#8221; Except, of course, you&#8217;re wrong. You don&#8217;t want to use GetFileSize at all. It has the following signature:<\/p>\n<pre class=\"code\" id=\"ctl00_rs1_mainContentContainer_ctl02\" space=\"preserve\">DWORD WINAPI GetFileSize(  __in       HANDLE <em>hFile<\/em>,\r\n\r\n__out_opt  LPDWORD <em>lpFileSizeHigh<\/em>\r\n\r\n);<\/pre>\n<p>Yes, it supports larger than 4GB files! How? A pointer to the high-order doubleword is passed in!  So how do you know if this errored? Return -1? WRONG! Because the high word could have been set and your file length could legitimately be 0x1ffffffff. So to find out if you actually had an error, you  <strong>must<\/strong> call  GetLastError! Instead of one call, you now have two.<\/p>\n<p>The Microsoft documentation even acknowledges that this is stupid: &#8220;Because of this behavior, it is recommended that you use      <strong>GetFileSizeEx<\/strong> instead.&#8221;<\/p>\n<p>GetFileSizeEx is presumably named &#8220;Ex&#8221; as in &#8220;i broke up with my ex because their API sucked.&#8221;<\/p>\n<p>You now have something that looks like this:<\/p>\n<pre class=\"code\" id=\"ctl00_rs1_mainContentContainer_ctl01\" space=\"preserve\">BOOL WINAPI GetFileSizeEx(  __in   HANDLE <em>hFile<\/em>,\r\n\r\n__out  PLARGE_INTEGER <em>lpFileSize<\/em>\r\n\r\n);<\/pre>\n<p>Which starts to look a little bit nicer. For a start, the return code of BOOL seems to indicate success or failure.<\/p>\n<p>You now get to provide a pointer to a LARGE_INTEGER. Which, if you missed it, a LARGE_INTEGER is:<\/p>\n<pre class=\"code\" id=\"ctl00_rs1_mainContentContainer_ctl02\" space=\"preserve\">typedef union _LARGE_INTEGER {  struct {\r\n\r\nDWORD LowPart;\r\n\r\nLONG HighPart;\r\n\r\n};\r\n\r\nstruct {\r\n\r\nDWORD LowPart;\r\n\r\nLONG HighPart;\r\n\r\n} u;\r\n\r\nLONGLONG QuadPart;\r\n\r\n} LARGE_INTEGER,\r\n\r\n*PLARGE_INTEGER;<\/pre>\n<p>Why this abomination? Well&#8230; &#8221; If your compiler has built-in support for 64-bit integers, use the <strong>QuadPart<\/strong> member to store the 64-bit integer. Otherwise, use the <strong>LowPart<\/strong> and <strong>HighPart<\/strong> members to store the 64-bit integer.&#8221;<\/p>\n<p>That&#8217;s right kiddies&#8230; if you&#8217;ve decided to loose from the get-go and have a compiler that doesn&#8217;t support 64-bit integers, you can still get the file size! Of course, you&#8217;re using a compiler that doesn&#8217;t have 64bit integer support&#8230; and the Microsoft documentation indicates that the GetFileSizeEx call requires Windows 2000&#8230; so it&#8217;s post y2k and you&#8217;re using a compiler without 64-bit ints? You have already lost.<\/p>\n<p>Oh, but you say something about binary compatibility for apps written in the old days (handwave something like that). Well&#8230; let&#8217;s see&#8230; IRIX will give you 64bit numbers in stat (stat64) unless you build with -o32 &#8211; giving you the old ABI. I just can&#8217;t see a use for GetFileSize&#8230;.. somebody please enlighten me.<\/p>\n<p>Which header would you include? Any Linux\/UNIX person would think of something logical &#8211; say  sys\/stat.h (Linux man page says sys\/types.h, sys\/stat.h and unistd.h). No, nothing sensible like that. It&#8217;s &#8220;Declared in WinBase.h; include Windows.h&#8221;.<\/p>\n<p>So&#8230; you thought that obviously somebody went through the API and gave you all this Ex function goodness to get rid of mucking about with parts of a 64bit int? You were wrong. Let me say it with this:<\/p>\n<pre class=\"code\" id=\"ctl00_rs1_mainContentContainer_ctl01\" space=\"preserve\">DWORD WINAPI GetCompressedFileSizeTransacted(\r\n  __in       LPCTSTR <em>lpFileName<\/em>,\r\n  __out_opt  LPDWORD <em>lpFileSizeHigh<\/em>,\r\n  __in       HANDLE <em>hTransaction<\/em>\r\n);<\/pre>\n<p>I&#8217;ll now tell you that this was introduced in Vista\/Server 2008.<\/p>\n<p>Obviously, you want to be able to use Transaction NTFS on Windows Vista with a compiler that doesn&#8217;t have 64 bit ints. Oh, and you must<strong> <\/strong>then make another function call to see if something went wrong?<\/p>\n<p>But you know what&#8230; perhaps we can get away from this complete and utter world of madness and use stat()&#8230;. or rather&#8230; perhaps _stati64().<\/p>\n<p>Well&#8230; you&#8217;d be fine except for the fact that these seem to <strong>lie<\/strong> <strong>to you<\/strong> (at least on Windows Server 2003 and Vista) &#8211; it seems that even Explorer can lie to you.<\/p>\n<p>But perhaps you&#8217;ve been barking up the wrong tree&#8230; you obviously don&#8217;t want to find the file size at all &#8211; what you want is to FindFirstFile! No, you don&#8217;t want FindFirstFileEx (in this case, Ex is for Extremely complicated). It&#8217;s meant to be faster too&#8230; you know, maybe.<\/p>\n<p>So remember kids, smoke your crack pipe &#8211; you&#8217;re going to need it if using this thing called the Microsoft Windows File Management Functions.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The first point I&#8217;d like to make is that you&#8217;re using a Microsoft Windows API, so you have already lost. You are just not quite aware of how much you have lost. A quick look around and you say &#8220;Ahh&#8230; &hellip; <a href=\"https:\/\/www.flamingspork.com\/blog\/2008\/02\/11\/getting-a-file-size-on-windows\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[18,14],"tags":[37,38,39,36,35],"class_list":["post-1008","post","type-post","status-publish","format-standard","hentry","category-grumble","category-mysql","tag-getfilesize","tag-getfilesizeex","tag-programming","tag-win32","tag-windows-api"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p5a6n8-gg","jetpack-related-posts":[{"id":891,"url":"https:\/\/www.flamingspork.com\/blog\/2007\/09\/19\/mysql-cluster-ndb-on-microsoft-windows\/","url_meta":{"origin":1008,"position":0},"title":"MySQL Cluster (NDB) on Microsoft Windows","author":"Stewart Smith","date":"2007-09-19","format":false,"excerpt":"Well... there's been some work. Even some in-progress patches. Being involved with this has just perfectly refreshed my memory of why I left the platform. Oh my it's a horrible, horrible platform. Everything from UI to API... ick. Expect something around soon....","rel":"","context":"In &quot;General&quot;","block_context":{"text":"General","link":"https:\/\/www.flamingspork.com\/blog\/category\/general\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1201,"url":"https:\/\/www.flamingspork.com\/blog\/2008\/09\/08\/setfilevaliddata-function-windows-now-with-added-fail\/","url_meta":{"origin":1008,"position":1},"title":"SetFileValidData Function (Windows) &#8211; Now with added FAIL","author":"Stewart Smith","date":"2008-09-08","format":false,"excerpt":"SetFileValidData Function (Windows) There seems to be two options on Win32 for preallocating disk space to files. Basically, I want a equivilent to posix_fallocate or the ever wonderful xfsctl XFS_IOC_RESVSP64 call. The idea being to (quickly) create a large file on disk that is stored efficiently (i.e. isn't fragmented). From\u2026","rel":"","context":"In &quot;mysql&quot;","block_context":{"text":"mysql","link":"https:\/\/www.flamingspork.com\/blog\/category\/work-et-al\/mysql\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1036,"url":"https:\/\/www.flamingspork.com\/blog\/2008\/03\/16\/windows-finally-gets-poll-wellwsapoll\/","url_meta":{"origin":1008,"position":2},"title":"Windows finally gets poll() (well&#8230;WSAPoll)","author":"Stewart Smith","date":"2008-03-16","format":false,"excerpt":"Found this today: Windows Core Networking : WSAPoll, A new Winsock API to simplify porting poll() applications to Winsock. Which means we should be able to squeeze some peformance out of Vista. Although, since poll() we've gone and moved on to much better things in the free world. As part\u2026","rel":"","context":"In &quot;mysql&quot;","block_context":{"text":"mysql","link":"https:\/\/www.flamingspork.com\/blog\/category\/work-et-al\/mysql\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1251,"url":"https:\/\/www.flamingspork.com\/blog\/2008\/11\/06\/goodbye-frm-or-at-least-the-steps-to-it\/","url_meta":{"origin":1008,"position":3},"title":"Goodbye FRM (or at least the steps to it)","author":"Stewart Smith","date":"2008-11-06","format":false,"excerpt":"Since before MySQL was MySQL, there has been the .FRM file. Of course, what it really wanted to be was \".form\" -\u00c2\u00a0 a file that stored how to display a form on your (green) CRT. Jan blogged earlier in the year on this still being there, even in MySQL 5.1\u2026","rel":"","context":"In &quot;drizzle&quot;","block_context":{"text":"drizzle","link":"https:\/\/www.flamingspork.com\/blog\/category\/work-et-al\/drizzle-work-et-al\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1869,"url":"https:\/\/www.flamingspork.com\/blog\/2010\/03\/23\/on-tableidentifier-and-the-death-of-path-as-a-parameter-to-storageengines\/","url_meta":{"origin":1008,"position":4},"title":"on TableIdentifier (and the death of path as a parameter to StorageEngines)","author":"Stewart Smith","date":"2010-03-23","format":false,"excerpt":"As anybody who has ever implemented a Storage Engine for MySQL will know, a bunch of the DDL calls got passed a parameter named \"path\". This was a filesystem path. Depending on what platform you were running, it may contain \/ or \\ (and no, it's not consistent on each\u2026","rel":"","context":"In &quot;drizzle&quot;","block_context":{"text":"drizzle","link":"https:\/\/www.flamingspork.com\/blog\/category\/work-et-al\/drizzle-work-et-al\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":3345,"url":"https:\/\/www.flamingspork.com\/blog\/2013\/05\/23\/mysql-vs-drizzle-plugin-api\/","url_meta":{"origin":1008,"position":5},"title":"MySQL vs Drizzle plugin APIs","author":"Stewart Smith","date":"2013-05-23","format":false,"excerpt":"There's a big difference in how plugins are treated in MySQL and how they are treated in Drizzle. The MySQL way has been to create a C API in front of the C++-like (I call it C- as it manages to take the worst of both worlds) internal \"API\". The\u2026","rel":"","context":"In &quot;code&quot;","block_context":{"text":"code","link":"https:\/\/www.flamingspork.com\/blog\/category\/code\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/www.flamingspork.com\/blog\/wp-json\/wp\/v2\/posts\/1008","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.flamingspork.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.flamingspork.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.flamingspork.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.flamingspork.com\/blog\/wp-json\/wp\/v2\/comments?post=1008"}],"version-history":[{"count":0,"href":"https:\/\/www.flamingspork.com\/blog\/wp-json\/wp\/v2\/posts\/1008\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.flamingspork.com\/blog\/wp-json\/wp\/v2\/media?parent=1008"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.flamingspork.com\/blog\/wp-json\/wp\/v2\/categories?post=1008"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.flamingspork.com\/blog\/wp-json\/wp\/v2\/tags?post=1008"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}