QB64 Phoenix Edition
File Listing To Arrays - Printable Version

+- QB64 Phoenix Edition (https://staging.qb64phoenix.com)
+-- Forum: QB64 Rising (https://staging.qb64phoenix.com/forumdisplay.php?fid=1)
+--- Forum: Prolific Programmers (https://staging.qb64phoenix.com/forumdisplay.php?fid=26)
+---- Forum: SMcNeill (https://staging.qb64phoenix.com/forumdisplay.php?fid=29)
+---- Thread: File Listing To Arrays (/showthread.php?tid=68)



File Listing To Arrays - SMcNeill - 04-20-2022

direntry.h  -- Grab this file.  It's a C header which QB64 will need to make use of.  Without it, the following won't run.

Copied, more or less  verbatim, from my post over at QB64.net:


Random1 asked elsewhere:
Quote:Is  there a way to save the output of FILES to a string or text file?

FILES "C:\MyFile\*.TXT"  to a string or  .txt file
So, I worked up this quick little routine to do just that...

Basic usage is rather simple:  Copy the header and put it up top in your program.  Copy the routine, put it at the end of your program.  Make certain "direntry.h" is in your QB64 directory when compiling...

Call the routine with:

GetFileList _CWD$, Dir(), File()

In this case, I'm just getting the file and subdirectory listings for the Current Working Directory (_CWD$), but you can get them for any directory that exists on your system...




Here's a way you can do what you want to, which is compatible for both Linux and Windows users (whereas SHELL may not always work across various platforms).

Code: (Select All)
DECLARE CUSTOMTYPE LIBRARY ".\direntry"
    FUNCTION load_dir& (s AS STRING)
    FUNCTION has_next_entry& ()
    SUB close_dir ()
    SUB get_next_entry (s AS STRING, flags AS LONG, file_size AS LONG)
END DECLARE

REDIM Dir(0) AS STRING, File(0) AS STRING


GetFileList _CWD$, Dir(), File()

PRINT "SUBDIRECTORIES"
FOR i = 1 TO UBOUND(dir)
    PRINT Dir(i),
NEXT
PRINT
SLEEP

PRINT "FILES": PRINT: PRINT
FOR i = 1 TO UBOUND(file)
    PRINT File(i),
NEXT
PRINT

SUB GetFileList (SearchDirectory AS STRING, DirList() AS STRING, FileList() AS STRING)
    CONST IS_DIR = 1
    CONST IS_FILE = 2
    DIM flags AS LONG, file_size AS LONG

    REDIM _PRESERVE DirList(100), FileList(100)
    DirCount = 0: FileCount = 0

    IF load_dir(SearchDirectory) THEN
        DO
            length = has_next_entry
            IF length > -1 THEN
                nam$ = SPACE$(length)
                get_next_entry nam$, flags, file_size
                IF flags AND IS_DIR THEN
                    DirCount = DirCount + 1
                    IF DirCount > UBOUND(DirList) THEN REDIM _PRESERVE DirList(UBOUND(DirList) + 100)
                    DirList(DirCount) = nam$
                ELSEIF flags AND IS_FILE THEN
                    FileCount = FileCount + 1
                    IF FileCount > UBOUND(filelist) THEN REDIM _PRESERVE FileList(UBOUND(filelist) + 100)
                    FileList(FileCount) = nam$
                END IF
            END IF
        LOOP UNTIL length = -1
        close_dir
    ELSE
    END IF
    REDIM _PRESERVE DirList(DirCount)
    REDIM _PRESERVE FileList(FileCount)
END SUB

Note, I set this up to separate the search results into files and subdirectories separately.

Note 2. You'll need to download "direntry.h" from the attachment below and copy it into your QB64 folder for this to work. It doesn't need to be with the EXE once you compile it, but it does need to be in the QB64 folder for compiling.

Useage is rather simple (even if it doesn't look it at first).

First, Copy the library declarations into the top of the program where you'd like to make use of this routine.

DECLARE CUSTOMTYPE LIBRARY ".\direntry"
    FUNCTION load_dir& (s AS STRING)
    FUNCTION has_next_entry& ()
    SUB close_dir ()
    SUB get_next_entry (s AS STRING, flags AS LONG, file_size AS LONG)
END DECLARE


Then set two arrays to hold the directory and file information for you:

REDIM Dir(0) AS STRING, File(0) AS STRING

Then when you're ready, call the routine to get that directory's subdirectory list and file list updated:

GetFileList _CWD$, Dir(), File()

At this point, you now have the listing of whichever directory you wanted stored in those two arrays, which you can use for whatever purpose you needed.

In this case, I just cheesily printed them to the screen:

PRINT "SUBDIRECTORIES"
FOR i = 1 TO UBOUND(dir)
    PRINT Dir(i),
NEXT
PRINT
SLEEP

PRINT "FILES": PRINT: PRINT
FOR i = 1 TO UBOUND(file)
    PRINT File(i),
NEXT
PRINT


And, at the end of your code, don't forget to include the routine itself:

Code: (Select All)
SUB GetFileList (SearchDirectory AS STRING, DirList() AS STRING, FileList() AS STRING)
    CONST IS_DIR = 1
    CONST IS_FILE = 2
    DIM flags AS LONG, file_size AS LONG

    REDIM _PRESERVE DirList(100), FileList(100)
    DirCount = 0: FileCount = 0

    IF load_dir(SearchDirectory) THEN
        DO
            length = has_next_entry
            IF length > -1 THEN
                nam$ = SPACE$(length)
                get_next_entry nam$, flags, file_size
                IF flags AND IS_DIR THEN
                    DirCount = DirCount + 1
                    IF DirCount > UBOUND(DirList) THEN REDIM _PRESERVE DirList(UBOUND(DirList) + 100)
                    DirList(DirCount) = nam$
                ELSEIF flags AND IS_FILE THEN
                    FileCount = FileCount + 1
                    IF FileCount > UBOUND(filelist) THEN REDIM _PRESERVE FileList(UBOUND(filelist) + 100)
                    FileList(FileCount) = nam$
                END IF
            END IF
        LOOP UNTIL length = -1
        close_dir
    ELSE
    END IF
    REDIM _PRESERVE DirList(DirCount)
    REDIM _PRESERVE FileList(FileCount)
END SUB


direntry.h   -- Remember, you need this file.  It's a C header which QB64 will need to make use of.  Without it, the following won't run.


RE: File Listing To Arrays - mpgcan - 05-14-2022

HTML entities gremlin

It looks like the HTML entities gremlin has mashed this page, more specifically translated the  ampersand incorrectly.
What is strange it seemed to like, the greater than and less than symbols these are OK.

These lines are located in two places:
    FUNCTION load_dir& (s AS STRING)
    FUNCTION has_next_entry& ()

Should be:
    FUNCTION load_dir& (s AS STRING)
    FUNCTION has_next_entry& ()


RE: File Listing To Arrays - SMcNeill - 05-14-2022

Updated to fix those. No idea where they came from, but many thanks in catching the issue.


RE: File Listing To Arrays - mnrvovrfc - 03-23-2023

On Manjaro KDE v22.0.4 for me this produces incorrect output.

See the screenshot below. One of the PNG files is being picked up as a directory for some reason.

I was forced to change the subprogram call to this:

Code: (Select All)
GetFileList environ$("HOME") + "/Downloads", Dir(), File()

changed away from _CWD$ function, because using this at the command line:

Code: (Select All)
$ $HOME/bin/qbpe/getfileslistex
$ # - OR -
$ /home/user/bin/qbpe/getfileslistex

showed me the list of files and subfolders of the directory that executable resides in.

I hope somebody could check this out in a different Linux distro. All I did was create four pictures with GIMP and exported them all to PNG, and I don't think there's anything special with "Downloads" when compared to the other Home members. The "four-faces..." file was the output for something I was working on when I stumbled upon this problem. It was from a QB64 program that saved to BMP, then "magick" program was used to convert to PNG.

(My user's log-in name isn't "user" and I'm not going to give it away, and I have given various names to a directory right under the Home which holds PPA's, AppImages and other such executables for Linux and Windows. This particular directory is called "bin" because it's what I came across in one of the distros. In a different Linux installation it's called "zapim". But it wasn't dominated by AppImages. It starts with "z" because I wanted it listed last in the file manager. The screenshots are supposed to have the user's log-in name in certain parts of the report from "ls" and "stat" programs.)


[Image: pic-file-is-not-a-directory.png]


RE: File Listing To Arrays - SpriggsySpriggs - 03-23-2023

Reminds me of the old bug this code had with Windows reporting extra directories or files. Can't remember which. Maybe the bug has remained but just now been seen again.


RE: File Listing To Arrays - SMcNeill - 03-23-2023

POSIX is generating a false flag for some reason for you.  It happens sometimes, and I have no clue why.

              IF flags AND IS_DIR THEN
                    DirCount = DirCount + 1
                    IF DirCount > UBOUND(DirList) THEN REDIM _PRESERVE DirList(UBOUND(DirList) + 100)
                    DirList(DirCount) = nam$
                ELSEIF flags AND IS_FILE THEN
                    FileCount = FileCount + 1
                    IF FileCount > UBOUND(filelist) THEN REDIM _PRESERVE FileList(UBOUND(filelist) + 100)
                    FileList(FileCount) = nam$
                END IF

When I first wrote this routine, we didn't have all the built-in commands which QB64 supports nowadays.  Change those bold lines to the following and see if our native routines do the trick for you:


IF _DirExists(nam$) THEN...

ELSEIF _FileExists(nam$) THEN...

END IF


RE: File Listing To Arrays - mnrvovrfc - 03-23-2023

Works well but only if the target directory has subdirectories. Otherwise it comes up only with single-dot and double-dot entries and no files.

In other words, the example program listed in this thread, but with the new QB64 functions involved, works because "qb64pe", or in my case "qbpe" has subdirectories. _CWD$ is set to that directory even if I launch the program from a different directory.

But when I attempt to use the "GetFilesList" subprogram to target another directory, which doesn't have children directories, it comes up empty.


RE: File Listing To Arrays - Petr - 03-25-2023

Quote:Works well but only if the target directory has subdirectories. Otherwise it comes up only with single-dot and double-dot entries and no files.


I'll just make sure. When the program is in a directory where there are files but no subdirectories, are you sure you're looking in the files field? Because the directory array will correctly contain those two dots a nothig else. I'm asking because it works fine for me (on windows).