find files pitfall
Posted: Thu Sep 23, 2021 4:42 pm
Guys,
In the German Xbase++ forum there´s been a discussion about the Directory() behaviour with the search pattern "862*.jpg".
https://www.xbaseforum.de/viewtopic.php ... 00#p139600
The problem can be reproduced with these two (long name ! ) files:
86220200630.JPG
86720210702.JPG
Because of the search pattern, only this file should be found.
86220200630.JPG
but both files are found !
Since VO and X# give the same result I took a closer look. The problem occurs when long filename are used and the
DOS 8.3 names feature is enabled on the search drive. You can check the current state of your drives when you open
a CMD box with admin rights and run the fsutil.exe.
fsutil 8dot3name query <Drive:>
These are the results of my "C:" and "D:" drives
8dot3 name creation is enabled on C:
8dot3 name creation is disabled on D:
When i search in my C:Test dir both files are found and only the search in my D:test directory shows one file. The
problem is that in the C:Test dir a comparison takes place with the short filenames and the long filenames. If the
pattern is found in the short filename it is interpreted as a hit.
That´s the content of my C:Test dir. As you can see both short file names start with "862"
From what i´ve found so far, the 8dot3name feature is enabled by default for the C drive only. That's the reason why
the search works in my D:test dir. It seems the only way to fix this behaviour is to disable the 8dot3name feature, or
to implement a own pattern search ?
That's my test code:
regards
Karl-Heinz
In the German Xbase++ forum there´s been a discussion about the Directory() behaviour with the search pattern "862*.jpg".
https://www.xbaseforum.de/viewtopic.php ... 00#p139600
The problem can be reproduced with these two (long name ! ) files:
86220200630.JPG
86720210702.JPG
Because of the search pattern, only this file should be found.
86220200630.JPG
but both files are found !
Since VO and X# give the same result I took a closer look. The problem occurs when long filename are used and the
DOS 8.3 names feature is enabled on the search drive. You can check the current state of your drives when you open
a CMD box with admin rights and run the fsutil.exe.
fsutil 8dot3name query <Drive:>
These are the results of my "C:" and "D:" drives
8dot3 name creation is enabled on C:
8dot3 name creation is disabled on D:
When i search in my C:Test dir both files are found and only the search in my D:test directory shows one file. The
problem is that in the C:Test dir a comparison takes place with the short filenames and the long filenames. If the
pattern is found in the short filename it is interpreted as a hit.
That´s the content of my C:Test dir. As you can see both short file names start with "862"
Code: Select all
C:Test>dir/X 862*.jpg
Volume in Laufwerk C: hat keine Bezeichnung.
Volumeseriennummer: DA00-F3C0
Verzeichnis von C:Test
23.09.2021 18:00 5 862202~1.JPG 86220200630.JPG
23.09.2021 18:00 5 8624E7~1.JPG 86720210702.JPG
2 Datei(en), 10 Bytes
0 Verzeichnis(se), 119.755.788.288 Bytes frei
the search works in my D:test dir. It seems the only way to fix this behaviour is to disable the 8dot3name feature, or
to implement a own pattern search ?
That's my test code:
Code: Select all
FUNCTION SearchFiles()
LOCAL aFiles, aDir AS ARRAY
LOCAL i AS DWORD
LOCAL hFile, hFind AS PTR
LOCAL cDir, cFile AS STRING
LOCAL struFindData IS _winWIN32_FIND_DATA
cDir := "c:Test"
// cDir := "d:Test"
aFiles := {}
// long filenames
AAdd(aFiles,"86220200630.JPG")
AAdd(aFiles,"86720210702.JPG")
FOR i := 1 TO ALen(aFiles)
IF ! File( cDir + aFiles [i])
IF ( hFile := FCreate( cDir + aFiles[i], FC_NORMAL ) ) != F_ERROR
FWrite( hFile, "Jimmy" )
FClose( hFile )
ENDIF
ENDIF
NEXT
aDir := Directory( cDir + "862*.JPG")
?
? "Directory() results"
?
FOR i := 1 UPTO ALen ( ADir )
? aDir [ i , F_NAME ]
NEXT
?
? "FindxxxFile results"
?
cFile := cDir + "862*.JPG"
IF ( hFind := FindFirstFile( String2Psz ( cFile ) , @struFindData) ) != INVALID_HANDLE_VALUE
// note: Psz2String ( @struFindData.cAlternateFileName ) shows the 8.3 filename if any
? Psz2String ( @struFindData.cFileName ) , Psz2String ( @struFindData.cAlternateFileName )
WHILE FindNextFile(hFind, @struFindData)
? Psz2String ( @struFindData.cFileName ) , Psz2String ( @struFindData.cAlternateFileName )
ENDDO
FindClose ( hFind )
ENDIF
#ifdef __XSHARP__
?
? "System.IO.Directory.GetFiles results"
?
VAR files := System.IO.Directory.GetFiles(cDir, "862*.JPG" )
FOREACH VAR f IN files
? System.IO.Path.GetFileName ( f )
NEXT
#endif
RETURN TRUE
Karl-Heinz