FindFirstFile / FindNextFile auf Netzlaufwerk findet nicht alles



  • Hallo zusammen,

    ich möchte gerne alle mp4-Dateien in einem Verzeichnis auflisten.
    Das Verzeichnis ist von einer dreambox (müsste also linux, samba mount sein) unter Windows 7 32Bit als Laufwerk hinzugefügt.

    Ich erhalte aber nicht alle Dateien, es fehlen ein paar. Ich habe keine Ahnung, wie ich das Problem angehen kann.
    Die return Werte der Find-Funktionen und auch GetLastError geben hier keinen Hinweis. Es ist, als würden die Dateien nicht existieren.

    Gebe ich als Filter . an, werden alle Dateien gefunden.
    Gebe ich den ganzen Namen der Datei an ( z.B. 'movie.mp4') wird diese auch gefunden.

    Hat jemand eine Idee, woran das liegen kann?
    Gibt es alternativen zu FindFirst-/FindNextFile?

    Keine Ahnung, ob das ein Hinweis auf mein Problem ist: Die Dateinamen, die ich bekomme, sind völlig unsortiert. Was ich beim Auflisten von lokalen Dateien nicht habe.

    hier mal der Code, evtl. hab ich ja doch was übersehen:

    char strFilter[_MAX_PATH]; ZeroMemory(strFilter, sizeof(char)*_MAX_PATH);
    strcat_s(strFilter, _MAX_PATH, strFolder);
    strcat_s(strFilter, _MAX_PATH, "\\");
    strcat_s(strFilter, _MAX_PATH, "*.mp4");
    
    WIN32_FIND_DATA findData; ZeroMemory(&findData, sizeof(WIN32_FIND_DATA));
    
    DWORD	fileCount	= 0;
    HANDLE	hFind		= FindFirstFile(strFilter, &findData);
    DWORD	lErr		= GetLastError();
    if (hFind ==  INVALID_HANDLE_VALUE)
    {
    	if (lErr == ERROR_FILE_NOT_FOUND)
    		TRACE("--> FindFirstFile: File Not Found\n");
    	else
    		TRACE("--> FindFirstFile: ErrNo: %d\n", lErr);
    }
    else
    {
    	// File gefunden
    	bool bIsFileFound = true;
    	do
    	{
    		fileCount++;
    		TRACE("%3d. ", fileCount); TRACE(findData.cFileName); TRACE("\n");
    
    		bIsFileFound	= FindNextFile(hFind, &findData);
    		lErr			= GetLastError();
    		if (!bIsFileFound)
    		{
    			if (lErr == ERROR_NO_MORE_FILES)
    				TRACE("--> FindNextFile: No More Files\n");
    			else
    				TRACE("--> FindNextFile: ErrNo: %d\n", lErr);
    		}
    	} while (bIsFileFound);
    	FindClose(hFind);
    }
    


  • Unicodezeichen iom Dateinamen? FindClose vergessen?

    So sieht meine aus:

    bool findFiles( const STRING &path, DIRECTORY_LIST &dirlist )
    {
    	doEnterFunction("findFiles");
    	doLogString( path );
    	bool success = false;
    
    #if defined( _Windows )
    	WIN32_FIND_DATAW	findDataW;
    	STRING				file;
    	uSTRING				wPath, tmpBuff;
    
    	wPath.fromString( path );
    
    	HANDLE fs = FindFirstFileW( wPath.getDataBuffer(), &findDataW );
    	;
    	if( fs != INVALID_HANDLE_VALUE )
    	{
    		size_t	numFiles = 0;
    		dirlist.clear();
    
    		do
    		{
    			DIRECTORY_ENTRY		&newElement = dirlist[numFiles++];
    
    			tmpBuff.fromWstring( findDataW.cFileName );
    			newElement.fileName = tmpBuff.toString();
    			newElement.fileSize.setValue( findDataW.nFileSizeLow, findDataW.nFileSizeHigh );
    			newElement.creationDate.setFileTime( findDataW.ftCreationTime );
    			newElement.modifiedDate.setFileTime( findDataW.ftLastWriteTime );
    			newElement.directory = findDataW.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
    
    		} while( FindNextFileW( fs, &findDataW ) );
    		FindClose( fs );
    
    		dirlist.resort();
    
    		success = true;
    	}
    
    #elif defined( __MACH__ ) || defined( __unix__ )
    
    	size_t			slashPos = path.searchRChar( DIRECTORY_DELIMITER );
    	STRING			myPath = slashPos != -1
    		? path.leftString( slashPos )
    		: STRING(".")
    	;
    	STRING			pattern = path + (size_t)(slashPos +1); 
    	struct dirent	*file;
    	DIR				*dir = opendir( myPath );
    	STRING			name;
    	STR_CHARSET     charSet;
    
    	if( pattern == "*.*" )
    		pattern = "*";
    	if( dir )
    	{
    		size_t	numFiles = 0;
    		dirlist.clear();
    		while( (file = readdir( dir )) != NULL )
    		{
    			doLogString( file->d_name );
    			name = file->d_name;
    			if( name.match( pattern ) )
    			{
    				DIRECTORY_ENTRY		&newElement = dirlist[numFiles++];
    
    				charSet = name.testCharSet();
    				if( charSet == STR_ANSI )
    					charSet = STR_UTF8;
    				name.setCharSet( charSet );
    
    				newElement.fileName = name;
    				newElement.directory = (file->d_type == DT_DIR);
    			}
    		}
    		closedir( dir );
    		dirlist.resort();
    
    		success = true;
    	}
    #else
    #	error "Unkown OS"
    #endif
    
    	doShowLog();
    	return success;
    }
    

    Ich habe bis jetzt immer alle Dateien bekommen. Egal ob Netzlaufwerk oder nicht.

    mfg Martin



  • Ja, FindClose hatte ich tatsächlich vergessen, thx.

    Unicode Zeichen sind keine enthalten. Ich habe aber trotzdem mal die Wide Charackter Funktionen benutzt und bekomme leider das gleiche Ergebnis.

    Inzwischen habe ich die gleichen Dateinamen mal auf einem anderen NAS getestet, dort läuft alles einwandfrei. Da muss irgendwas im argen mit der dreambox sein. Wobei der Windows Dateiexplorer keine Probleme hat die Dateien aufzulisten, verwendet der dann nicht die Find-Funktionen?



  • Nun, dann fällt mir leider auch nicht mehr viel ein. Vielleicht gibt es ein Problem mit der Groß-/Kleinschreibung?

    Darüber hinaus Du schriebst ja, daß Du beim Suchmuster "." ja alle Dateien erhälst, ich denke der Explorer wird auch nix anderes machen.

    Was Du auch noch schauen kannst, ob irgendwelche Attribute wie System oder Hidden gesetzt sind.

    Bekommst Du eine Terminalverbindung (Telnet, RSH, SSH) zur Dream Box? Dann prüfe auch mal die Berechtigungen und die Unixattribute etc.



  • Ja, Telnet geht. Die Attribute unterscheiden sich nicht von den Dateien, die gefunden werden.

    Ich werde dann erstmal alle Filenamen holen und dann selbst filtern.
    Danke Dir für deine Mühe!

    Grüße,
    mathi



  • mathi schrieb:

    Ja, Telnet geht. Die Attribute unterscheiden sich nicht von den Dateien, die gefunden werden.

    Ich werde dann erstmal alle Filenamen holen und dann selbst filtern.
    Danke Dir für deine Mühe!

    Grüße,
    mathi

    Da fällt mir noch was ein, was Du prüfen kannst. Gibt es vielleicht führende oder folgende Leerzeichen im Namen? Die werden gerne übersehen.

    mfg Martin



  • Leider nein, Leerzeichen oder Sonderzeichen, welche evtl. nicht dargestellt werden gibt es nicht im Namen.

    Ich habe die Find Funktionen auch schon explizit dynamisch gegen die aktuelle Kernel32.dll gelinkt, falls irgendwas am SDK faul sein sollte. Und die dreambox hat heute auch nochmal das aktuellste Software Image bekommen.



  • mgaeckler schrieb:

    Unicodezeichen iom Dateinamen? FindClose vergessen?

    So sieht meine aus:

    bool findFiles( const STRING &path, DIRECTORY_LIST &dirlist )
    {
    	doEnterFunction("findFiles");
    	doLogString( path );
    	bool success = false;
    
    #if defined( _Windows )
    	WIN32_FIND_DATAW	findDataW;
    	STRING				file;
    	uSTRING				wPath, tmpBuff;
    
    ...
    

    Ich habe bis jetzt immer alle Dateien bekommen. Egal ob Netzlaufwerk oder nicht.

    mfg Martin

    Netter Ansatz das Problem sowohl für UNIX als auch für Windows zu lösen. Leider kann man (zumindest unter Windows)
    mit dem vorgeschlagenen Code garnichts anfangen, da diverse Deklarationen fehlen:

    STRING
    DIRECTORY_LIST
    DIRECTORY_ENTRY
    uSTRING
    
    newElement
    doEnterFunction( )
    doLogString( )
    doShowLog()
    

    wäre es möglich die Deklarationen noch "beizulegen" ?

    Microsofts Vorschlag zu dem Thema sieht so aus:
    Listing the Files in a Directory
    http://msdn.microsoft.com/de-de/library/windows/desktop/aa365200.aspx



  • merano schrieb:

    mgaeckler schrieb:

    Unicodezeichen iom Dateinamen? FindClose vergessen?

    So sieht meine aus:

    bool findFiles( const STRING &path, DIRECTORY_LIST &dirlist )
    {
    	doEnterFunction("findFiles");
    	doLogString( path );
    	bool success = false;
    
    #if defined( _Windows )
    	WIN32_FIND_DATAW	findDataW;
    	STRING				file;
    	uSTRING				wPath, tmpBuff;
    
    ...
    

    Ich habe bis jetzt immer alle Dateien bekommen. Egal ob Netzlaufwerk oder nicht.

    mfg Martin

    Netter Ansatz das Problem sowohl für UNIX als auch für Windows zu lösen. Leider kann man (zumindest unter Windows)
    mit dem vorgeschlagenen Code garnichts anfangen, da diverse Deklarationen fehlen:

    STRING
    DIRECTORY_LIST
    DIRECTORY_ENTRY
    uSTRING
    
    newElement
    doEnterFunction( )
    doLogString( )
    doShowLog()
    

    wäre es möglich die Deklarationen noch "beizulegen" ?

    Microsofts Vorschlag zu dem Thema sieht so aus:
    Listing the Files in a Directory
    http://msdn.microsoft.com/de-de/library/windows/desktop/aa365200.aspx

    Ich überlege mir schon seit geraumer Zeit die Bibliothek zu veröffentlichen. Allerdings entspricht die Qualität meiner Dokumentation der Lib nicht meinen Vorstellungen. Genauer gesagt die Quantität. Sie ist nämlich derzeit praktisch 0. Deshalb tue ich mich schwer, diese zu veröffentlichen.

    Hier im konkreten Fall sollte es aber einfach sein, das erforderliche selbst zu erstellen:

    STRING entspricht im wesentlichen std:string. Keine Ahnung ob std:string das auch kann aber meine STRING-klasse weiß halt auch, ob die aktuelle Kodierung ASCII, ANSI oder UTF-8 ist.

    DIRECTORY_LIST ist einfach nur ein ARRAY von DIRECTORY_ENTRY. entspricht also im wesentlichen std::vector<DIRECTORY_ENTRY>.

    DIRECTORY_ENTRY sieht bei mir so aus:

    struct DIRECTORY_ENTRY
    {
    	STRING 			fileName;
    	uint64			fileSize;
    	GAK_DATE_TIME	creationDate, modifiedDate;
    	bool			directory;
    }
    

    GAK_DATE_TIME ist einfach nur ein Zeitstempel, kannste auch time_t benutzen.

    uSTRING ist ein wchar_t array, das eine Funktion zu Konvertierung in UTF-8 mitbringt.

    die drei Funktionen, die mit do beginnen, sind Debuggingfunktionen und werden ausgeblendet, wenn release code generiert wird.

    Miitlerweile habe ich die Funktion auch ein wenig geändert:
    findFiles ist jetzt ein Member von DIRECTORY_LIST. Das Element fileSize von DIRECTORY_ENTRY ist jetzt auch ein 64-Bit Integer und keine Struktur mehr. Der Array-Container hat jetzt auch eine Memberfunktion createElement. Die Unix-Version füllt nun auch alle Felder:

    bool DIRECTORY_ENTRY::findFile( const STRING &fileName )
    {
    		bool		success;
    #ifdef __BORLANDC__
    		struct stati64	buf;
    
    		if( !strStat64( fileName, &buf ) )
    #else
    		struct stat	buf;
    
    		if( !strStat( fileName, &buf ) )
    #endif
    		{
    			this->fileName = fileName;
    			directory = S_ISDIR( buf.st_mode );
    			fileSize = buf.st_size;
    			creationDate = buf.st_ctime;
    			modifiedDate = buf.st_mtime;
    			success = true;
    		}
    		else
    		{
    			this->fileName = "";
    			directory = false;
    			fileSize = 0;
    			creationDate = 0;
    			modifiedDate = 0;
    			success = false;
    		}
    
    		return success;
    }
    
    bool DIRECTORY_LIST::findFiles( const STRING &path )
    {
    	doEnterFunction("findFiles");
    	doLogString( path );
    	bool success = false;
    
    #if defined( _Windows )
    	WIN32_FIND_DATAW	findDataW;
    	STRING				file;
    	uSTRING				wPath, tmpBuff;
    
    	wPath.fromString( path );
    
    	HANDLE fs = FindFirstFileW( wPath.getDataBuffer(), &findDataW );
    	;
    	if( fs != INVALID_HANDLE_VALUE )
    	{
    		clear();
    
    		do
    		{
    			DIRECTORY_ENTRY		&newElement = createElement();
    
    			tmpBuff.fromWstring( findDataW.cFileName );
    			newElement.fileName = tmpBuff.toString();
    			newElement.fileSize = (findDataW.nFileSizeHigh << 32) | findDataW.nFileSizeLow;
    			newElement.creationDate.setFileTime( findDataW.ftCreationTime );
    			newElement.modifiedDate.setFileTime( findDataW.ftLastWriteTime );
    			newElement.directory = findDataW.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
    
    		} while( FindNextFileW( fs, &findDataW ) );
    		FindClose( fs );
    
    		resort();
    
    		success = true;
    	}
    
    #elif defined( __MACH__ ) || defined( __unix__ )
    
    	size_t			slashPos = path.searchRChar( DIRECTORY_DELIMITER );
    	STRING			myPath = slashPos != -1
    		? path.leftString( slashPos )
    		: STRING(".")
    	;
    	STRING			pattern = path + (size_t)(slashPos +1);
    	struct dirent	*file;
    	DIR				*dir = opendir( myPath );
    	STRING			name;
    	STR_CHARSET     charSet;
    
    	if( pattern == "*.*" )
    		pattern = "*";
    	if( dir )
    	{
    		clear();
    		while( (file = readdir( dir )) != NULL )
    		{
    			doLogString( file->d_name );
    			name = file->d_name;
    			if( name.match( pattern ) )
    			{
    				DIRECTORY_ENTRY		&newElement = createElement();
    
    				charSet = name.testCharSet();
    				if( charSet == STR_ANSI )
    					charSet = STR_UTF8;
    				name.setCharSet( charSet );
    
    				newElement.findFile( myPath + DIRECTORY_DELIMITER + name );
    				newElement.fileName = name;
    				newElement.directory = (file->d_type == DT_DIR);
    			}
    		}
    		closedir( dir );
    		resort();
    
    		success = true;
    	}
    #else
    #	error "Unkown OS"
    #endif
    
    	doShowLog();
    	return success;
    }
    

    Hier noch eine Anmerkung:

    strStat ist unter Nixen einfach nur ein Makro auf stat. Unter Nixen werden Dateinamen UTF-8 kodiert und das versteht auch stat und STRING. Windows benutzt entweder ANSI oder UNICODE wenn strStat im übergebenen STRING eine UTF-8 Kodierung findet, wird der String in UNICODE gewandelt und die entsprechenden Funktionen benutzt. Ansonsten wird die ganz normale Funktion stat verwendet. Allerding hab ich die auch schon patchen müssen, weil die Runtime-Libs von Borland und Kleinweich falsche Zeiten liefern, wenn die Dateien im Winter erstellt bzw. geändert wurden und stat im Sommer aufgerufen wird und umgekehrt. Angeblich machen die das absichtlich wegen dem alten FAT-Dateisystem, das ja lokale Zeit speichert statt UTC.

    mfg Martin



  • Vielen Dank mgaeckler fuer die Beschreibung der Zutaten.

    Nachdem man VS einiges nun "schmackhaft" gemacht hat mit:

    typedef std::basic_string<TCHAR> STRING;
    typedef unsigned __int64  uint64;
    
    struct DIRECTORY_ENTRY { 
        STRING    fileName; 
        uint64    fileSize; 
        time_t    creationDate, modifiedDate;  // ein Zeitstempel
        bool      directory; 
    };  
    
    typedef std::vector<DIRECTORY_ENTRY>  DIRECTORY_LIST;
    
    void doEnterFunction(char *txt) {};
    void doLogString( const STRING ) {};
    

    fehlt immer noch die komplette Klasse uSTRING.

    Wäre es nicht besser das ganze mit C++-Standard zu erschlagen ?



  • merano schrieb:

    Vielen Dank mgaeckler fuer die Beschreibung der Zutaten.

    fehlt immer noch die komplette Klasse uSTRING.

    Wäre es nicht besser das ganze mit C++-Standard zu erschlagen ?

    Die Definition von uSTRING wird Dir nicht gefallen:

    class uSTRING : public ARRAY<wchar_t>
    {
    	public:
    	const wchar_t *getString( void )
    	{
    		return getDataBuffer();
    	}
    	void decodeUTF8( const STRING &src );
    	STRING encodeUTF8( void );
    	STRING toString( void );
    	void fromString( const STRING &src );
    	void fromWstring( const wchar_t	*src );
    };
    

    Die ganze Bibliothek ist eine gewachsende Lib, deren Ursprünge 1988 auf einem Atari ST mit Turbo C angelegt wurden. 1990 wurde dann angefangen vielen Sachen nach Turbo C++ zu migrieren und Mitte der 90er auf Gnu C++ unter Linux (in der Zeit habe ich dann auch angefangen die C bzw. Atarikompatibilität nicht mehr zu verfolgen) und Anfang 2000 kam dann MACH dazu.

    Viele Klassen, insbesonders STRING, ARRAY etc wurden angelegt als es halt noch keinen Standard gab.

    mfg Martin



  • mgaeckler schrieb:

    Die Definition von uSTRING wird Dir nicht gefallen:

    Stimmt. Egal, danke für die Infos. Ich frag nicht weiter ...

    mgaeckler schrieb:

    Viele Klassen, insbesonders STRING, ARRAY etc wurden angelegt als es halt noch keinen Standard gab.

    Ich weiss nur zu gut wovon Du du berichtest, war live dabei. Turbo Pascal, Turbo C, Assembler und manchmal gemixt im selben Programm. War halt so ...

    Und der gute alte 68000 - das waren Zeiten ...



  • merano schrieb:

    Ich weiss nur zu gut wovon Du du berichtest, war live dabei. Turbo Pascal, Turbo C, Assembler und manchmal gemixt im selben Programm. War halt so ...

    Und der gute alte 68000 - das waren Zeiten ...

    Turbo Pascal auf dem Atari? Soweit ich weiß wurde die Auslieferung gestoppt noch bevor der erste Diskettensatz verschickt wurde. Damit dürfte es außer mir nicht sehr viele Leute gegeben haben, die das gesehen haben.

    mfg Martin



  • Hallo,
    als alter TP-Programmierer möchte ich auch gerne noch etwas beitragen.
    Auch wenn das hier C++ ist - Auch ich träume von alten ATARI-ST-Zeiten ...

    Wenn FindFirstFile / FindNextFile nicht alles findet,
    könnte es vielleicht ein Problem mit der Übertragung geben?
    Wie ist denn die DreamBox an das System angeschlossen?
    Über USB vielleicht? Oder FireWire?
    Könnte es vielleicht sein, daß das System einige der Informationen
    "verschluckt", bevor sie beim Programm ankommen ?

    Ich hatte das Problem auch schon unter DOS & Windows unter TP -
    ich weiß jetzt aber nicht mehr, woran das seinerzeit lag ...

    Mit freundlichem Gruß,

    Guenni60



  • @mathi
    Was bekommst du denn wenn du ne Konsole ( cmd.exe ) aufmachst und dort dir \\Pfad\zum\NAS\Verzeichnis\*.mp4 eingibst?
    Explorer ist mMn. ziemlich uninteressant, denn der wird kaum direkt FindFirstFile/FindNextFile verwenden. Bei der " dir " Implementierung in cmd.exe gehe ich aber davon aus dass die im Endeffekt nix anderes macht.
    Und wenn die Files da auch fehlen, dann ist vermutlich einfach die SMB Implementierung in der NAS fehlerhaft.

    @Guenni60

    Guenni60 schrieb:

    Wie ist denn die DreamBox an das System angeschlossen?
    Über USB vielleicht? Oder FireWire?

    Gar nicht direkt, Zugriff über's Netzwerk.

    Das Verzeichnis ist von einer dreambox (müsste also linux, samba mount sein) unter Windows 7 32Bit als Laufwerk hinzugefügt.

    Und Samba ist die (bzw. eine) SMB Implementierung für Linux. Und SMB == Das Protokoll welches Windows für "Netzwerkfreigaben" verwendet.


Anmelden zum Antworten