Benutzer mit den meisten Antworten
Falsche Dateigröße

Frage
-
Unter Windows 7 Ultimate 64Bit erhalte ich mit _stat in seltenen Fällen eine falsche Dateigröße. Dabei wird im Prinzip der letzte Schreibvorgang unterschlagen.
Auch die Dateieigenschaften im Windowsexplorer enthalten die falsche Dateigröße. FindFirstFile auf die Datei ergibt ebenfalls die falsche Größe.
Nachdem die Datei z.B. ins Notepad geladen wurde, wird die Dateigröße im Filesystem korrigiert. Ansonsten bleibt stundenlang die falsche Dateigröße im Dateisystem.
Das Problem lässt sich einfach reproduzieren.
#include <windows.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> typedef union { struct myI64 { unsigned long ul; unsigned long uh; } v1; __int64 v2; } int64; int CheckLen(char *filename, __int64 *filelen) { int64 i64; HANDLE hFind; WIN32_FIND_DATA fd; struct _stati64 sb; hFind=FindFirstFile(filename, &fd); if(hFind!=INVALID_HANDLE_VALUE) { i64.v1.ul=fd.nFileSizeLow; i64.v1.uh=fd.nFileSizeHigh; FindClose(hFind); if(i64.v2 != *filelen) { printf("Filesize differs: %I64d (%I64d)\n", *filelen, i64.v2); if(!_stati64(filename, &sb)) printf("Filesize with stat: %I64d\n", sb.st_size); return 0; } } return 1; } int appendBuf(char *filename, char *buf, int size, __int64 *filelen) { HANDLE hFile=CreateFile(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); DWORD dwh=0, dwl=0, dw; int result=1; if(hFile!=INVALID_HANDLE_VALUE) { dwl=SetFilePointer(hFile, 0, &dwh, FILE_END); if(WriteFile(hFile, buf, size, &dw, NULL)) { *filelen+=dw; } else { result=0; } CloseHandle(hFile); } else result=0 return result; } int main(int argc, char **argv) { char *filename; __int64 filelen=0; char buf[256]; int i; if(argc==2) filename=argv[1]; else return 1; for(i=0; i<256; i++) buf[i]='A' + ((rand()*32)/RAND_MAX); do { if(!appendBuf(filename, buf, 51, &filelen)) return 1 } while(CheckLen(filename, &filelen)); return 0; }
Um schneller den Fehler zu erhalten, muss man einfach eine 2. Instanz des Programms mit einer 2. Datei starten.
Unter Windows XP 32bit kann ich diesen Fehler nicht reproduzieren. Es liegt dabei auch nicht an zu großen Dateien.- Bearbeitet Robert BreitenhoferModerator Mittwoch, 24. Februar 2010 13:44 Formatierung
- Typ geändert Robert BreitenhoferModerator Donnerstag, 25. Februar 2010 12:36 Frage
- Verschoben Robert BreitenhoferModerator Donnerstag, 25. Februar 2010 12:36 C++ (Von:Windows 7)
Antworten
-
Hallo FredSt!
> Danke für die Antworten.
Also, hier die Antwort der MS Windows Produkt-Gruppe:
NTFS directory information is typically not updated in a synchronous
fashion and FindFirstFile keys off NtQueryDirectoryFile (i.e. reading
directory dup info) and thus are prone to getting stale data, but there
are other API's that should get you live data like GetFileSize(). There
is some information like file size duplicated in the file record and in
the directory entry that points to the file record (to facilitate speedy
directory enumerations). The directory entry is updated lazily (for
performance reasons). Hence the discrepancy.
Documentation of FindFirstFile
http://msdn.microsoft.com/en-us/library/aa364418(VS.85).aspx notes the
following:
Note In rare cases, file information on NTFS file systems may not be
current at the time you call this function. To be assured of getting the
current file information, call the GetFileInformationByHandle function.
Das sollte Dir eigentlich weiterhelfen. Es ist also "by design".
Jochen Kalmbach (MVP VC++)- Als Antwort vorgeschlagen Jochen Kalmbach Dienstag, 9. März 2010 20:52
- Als Antwort markiert Robert BreitenhoferModerator Mittwoch, 10. März 2010 09:19
-
Noch als Info: Wenn Du vor dem CloseHandle die Funktion "FlushFileBuffers" aufrufst, tritt das Problem nicht mehr auf...
Jochen Kalmbach (MVP VC++)- Als Antwort vorgeschlagen Martin RichterModerator Montag, 1. März 2010 07:18
- Als Antwort markiert Robert BreitenhoferModerator Mittwoch, 3. März 2010 07:41
Alle Antworten
-
Das ist eine gute Frage ;)
Es scheint so, also ob da tatsächlich irgendwas "optimiert" wird...
Hab das Programm mal Unicode-Tauglich gemacht und noch die Testdatei vorher gelöscht...
Werde es mal der MS Produkt-Gruppe melden... ich hab aber irgendwo gelesen, dass es im NTFS Dateisystem irgendwelche "optimierungen" gab, was vielleicht zu diesem Phänomen führen könnte...
Hier mal der "korrigierte" Code:
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <sys/types.h> #include <sys/stat.h> typedef union { struct myI64 { unsigned long ul; unsigned long uh; } v1; __int64 v2; } int64; int CheckLen(LPCTSTR filename, __int64 *filelen) { int64 i64; HANDLE hFind; WIN32_FIND_DATA fd; struct _stati64 sb; hFind=FindFirstFile(filename, &fd); if(hFind!=INVALID_HANDLE_VALUE) { i64.v1.ul=fd.nFileSizeLow; i64.v1.uh=fd.nFileSizeHigh; FindClose(hFind); if(i64.v2 != *filelen) { printf("Filesize differs: %I64d (%I64d)\n", *filelen, i64.v2); if(!_tstat64(filename, &sb)) printf("Filesize with stat: %I64d\n", sb.st_size); return 0; } } return 1; } int appendBuf(LPCTSTR filename, char *buf, int size, __int64 *filelen) { HANDLE hFile=CreateFile(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); LONG dwh=0; DWORD dwl=0, dw; int result=1; if(hFile!=INVALID_HANDLE_VALUE) { dwl=SetFilePointer(hFile, 0, &dwh, FILE_END); if(WriteFile(hFile, buf, size, &dw, NULL)) { *filelen+=dw; } else { result=0; } CloseHandle(hFile); } else result=0; return result; } int _tmain(int argc, TCHAR **argv) { LPTSTR filename; if(argc==2) filename=argv[1]; else { printf("please provide a test-filename!\n"); return 1; } char buf[256]; for(int i=0; i<256; i++) buf[i]='A' + ((rand()*32)/RAND_MAX); // be sure the file is deleted before we start testing...... _tremove(filename); __int64 filelen=0; do { if(!appendBuf(filename, buf, 51, &filelen)) return 1; } while(CheckLen(filename, &filelen)); return 0; }
Jochen Kalmbach (MVP VC++) -
Nur als Hinweis noch:
Falls Du oder Deine Firma eine MSDN-Subscription hast, rate ich Dir den MS-Produkt-Support zu kontaktieren. Das scheint mir ein Fall für den zu sein...
Meine Anfrage an die Produktgruppe hat oft nicht den nötigen "Druck" ;)
Jochen Kalmbach (MVP VC++) -
Noch als Info: Wenn Du vor dem CloseHandle die Funktion "FlushFileBuffers" aufrufst, tritt das Problem nicht mehr auf...
Jochen Kalmbach (MVP VC++)- Als Antwort vorgeschlagen Martin RichterModerator Montag, 1. März 2010 07:18
- Als Antwort markiert Robert BreitenhoferModerator Mittwoch, 3. März 2010 07:41
-
Hallo FredSt!
> FlushFileBuffers hilft tatsächlich. Leider leidet darunter die
> Performance. Ohne FlushFileBuffers wird die Datei ca 5 bis 6 mal so
> schnell gefüllt.
Ja... ich würde Dir deshalb empfehlen Dich an den MS Product Support zu
wenden!
Es sieht mir nach einem Bug aus...
Siehe:
https://msdn.microsoft.com/en-us/subscriptions/bb266240.aspx
Tel.: 0180 5 67 22 55
Jochen Kalmbach (MVP VC++) -
Hallo FredSt!
> Danke für die Antworten.
Also, hier die Antwort der MS Windows Produkt-Gruppe:
NTFS directory information is typically not updated in a synchronous
fashion and FindFirstFile keys off NtQueryDirectoryFile (i.e. reading
directory dup info) and thus are prone to getting stale data, but there
are other API's that should get you live data like GetFileSize(). There
is some information like file size duplicated in the file record and in
the directory entry that points to the file record (to facilitate speedy
directory enumerations). The directory entry is updated lazily (for
performance reasons). Hence the discrepancy.
Documentation of FindFirstFile
http://msdn.microsoft.com/en-us/library/aa364418(VS.85).aspx notes the
following:
Note In rare cases, file information on NTFS file systems may not be
current at the time you call this function. To be assured of getting the
current file information, call the GetFileInformationByHandle function.
Das sollte Dir eigentlich weiterhelfen. Es ist also "by design".
Jochen Kalmbach (MVP VC++)- Als Antwort vorgeschlagen Jochen Kalmbach Dienstag, 9. März 2010 20:52
- Als Antwort markiert Robert BreitenhoferModerator Mittwoch, 10. März 2010 09:19