Page 1 of 1

FileExists

Posted: Sat Feb 11, 2017 8:16 pm
by Josh
Maybe we can have a nativ command FileExists(). Look at the following example, GetFileAttributes() is about 3 times faster than FileSize(). I don't know if there is also a similar possibility for Mac/Linux.

Code: Select all

Procedure.i FileExists (FileName$)
  Define FileAttributes

  CompilerSelect #PB_Compiler_OS

    CompilerCase #PB_OS_Windows
      If GetFileAttributes (FileName$) & #FILE_ATTRIBUTE_DIRECTORY = #False
        ProcedureReturn #True
      EndIf

    CompilerCase #PB_OS_Linux
      If FileSize (FileName$) > -1
        ProcedureReturn #True
      EndIf

    CompilerCase #PB_OS_MacOS
      If FileSize (FileName$) > -1
        ProcedureReturn #True
      EndIf

  CompilerEndSelect

EndProcedure

Re: FileExists

Posted: Tue Feb 14, 2017 10:13 am
by Shardik
The following cross-platform example checks if a file exists. I have tested it succesfully on these operating systems:
- Linux Mint 18 'Sarah' x86 with PB 5.44 x86 with GTK2 and GTK3 in ASCII and Unicode mode
- Lubuntu 14.04 x86 with PB 5.44 x86 with GTK2 and GTK3 in ASCII and Unicode mode
- MacOS 10.6.8 'Snow Leopard with PB 5.44 x86 in ASCII and Unicode mode
- Windows XP SP3 x86 with PB 5.44 x86 in ASCII and Unicode mode
- Windows 7 SP1 x64 with PB 5.44 x86 and x64 in ASCII and Unicode mode
- Windows 8.1 x64 with PB 5.44 x86 and x64 in ASCII and Unicode mode

Code: Select all

Procedure.I FileExists(Filename.S)
  CompilerSelect #PB_Compiler_OS
    CompilerCase #PB_OS_Windows
      ProcedureReturn PathFileExists_(Filename)
    CompilerCase #PB_OS_Linux
      Protected UTF8Filename.S = Space(StringByteLength(Filename, #PB_UTF8) + 1)
      PokeS(@UTF8Filename, Filename, -1, #PB_UTF8)
      ProcedureReturn g_file_test_(UTF8Filename, #G_FILE_TEST_EXISTS)
    CompilerCase #PB_OS_MacOS
      ProcedureReturn CocoaMessage(0, CocoaMessage(0, 0,
        "NSFileManager defaultManager"),
        "fileExistsAtPath:$", @Filename)
  CompilerEndSelect
EndProcedure

; ----- Output on Linux and MacOS: 0, Windows: 1 
Debug "FileExists: " + FileExists(#PB_Compiler_Home + "Compilers/PBCompiler.Exe")

; ----- Output on Linux and MacOS: 1, Windows: 0
Debug "FileExists: " + FileExists(#PB_Compiler_Home + "compilers/pbcompiler")

Re: FileExists

Posted: Tue Feb 14, 2017 2:50 pm
by Josh
You can not use PathFileExists_ to check whether a file exists or not. As the name implies, it checks to see if a file or path exists with this name.

Re: FileExists

Posted: Tue Feb 14, 2017 4:35 pm
by Kiffi
Josh wrote:You can not use PathFileExists_ to check whether a file exists or not. As the name implies, it checks to see if a file or path exists with this name.
MSDN wrote: PathFileExists function
Determines whether a path to a file system object such as a file or folder is valid.
Greetings ... Peter

Re: FileExists

Posted: Tue Feb 14, 2017 4:45 pm
by skywalk
The request is FileExists.
If a folder exists with the same name as a queried file name, then PathFileExists_(Filename$) returns #True, which is not. :wink:

Re: FileExists

Posted: Tue Feb 14, 2017 7:54 pm
by Shardik
skywalk wrote:The request is FileExists.
If a folder exists with the same name as a queried file name, then PathFileExists_(Filename$) returns #True, which is not. :wink:
skywalk is correct in that the Windows part of my example from above is not fool proof. When calling with an existing folder name like

Code: Select all

Debug "FileExists: " + FileExists(#PB_Compiler_Home + "Compilers")
the procedure will return #True. On the other side: the procedure declaration contains the parameter Filename.S, so that it should be clear that a filename is required. So if you want to prevent a #True for an existing folder name you should use Josh's alternative. Although Josh's alternative has the drawback that you would have to use a longer winded code if a device such as a multi card interface with no cards plugged in is queried (in order to suppress an error message). Such an example had already been posted by RichardL in 2008.

For your conveniance I have changed the Windows part of my example from above with Josh's short (and potentially displaying an unwanted error message requester) code:

Code: Select all

Procedure.I FileExists(Filename.S)
  CompilerSelect #PB_Compiler_OS
    CompilerCase #PB_OS_Windows
      If GetFileAttributes(FileName) & #FILE_ATTRIBUTE_DIRECTORY = #False
        ProcedureReturn #True
      EndIf
    CompilerCase #PB_OS_Linux
      Protected UTF8Filename.S = Space(StringByteLength(Filename, #PB_UTF8) + 1)
      PokeS(@UTF8Filename, Filename, -1, #PB_UTF8)
      ProcedureReturn g_file_test_(UTF8Filename, #G_FILE_TEST_EXISTS)
    CompilerCase #PB_OS_MacOS
      ProcedureReturn CocoaMessage(0, CocoaMessage(0, 0,
        "NSFileManager defaultManager"),
        "fileExistsAtPath:$", @Filename)
  CompilerEndSelect
EndProcedure

; ----- Output on Linux and MacOS: 0, Windows: 1
Debug "FileExists: " + FileExists(#PB_Compiler_Home + "Compilers/PBCompiler.Exe")

; ----- Output on Linux and MacOS: 1, Windows: 0
Debug "FileExists: " + FileExists(#PB_Compiler_Home + "compilers/pbcompiler")

Re: FileExists

Posted: Tue Feb 14, 2017 7:56 pm
by Kiffi
skywalk wrote:If a folder exists with the same name as a queried file name, then PathFileExists_(Filename$) returns #True, which is not. :wink:
ah, ok, I have not considered that.

Thanks for clarification & Greetings ... Peter

Re: FileExists

Posted: Wed Feb 15, 2017 1:26 am
by Dude
Josh wrote:GetFileAttributes() is about 3 times faster than FileSize().
But... checking for a file's existence isn't something that's done over and over repeatedly, right? What benefit is there for having it check a little faster?

Re: FileExists

Posted: Wed Feb 15, 2017 1:45 am
by Thunder93
File synchronization software would benefit from it. :wink:

Re: FileExists

Posted: Wed Feb 15, 2017 4:02 am
by skywalk
Didn't know it was 3x faster, but I agree with the diminishing returns in comparison with more often used checksums and date modified attributes.