folderitem + child is nil and gives exception

so i am presupposing a file(s) does not exist

if I use this code with children i get an Exception and InvoiceFolder is Nil
InvoiceFolder = AppFolder.Child(“xxx”).Child(“Data”).Child(“xxx”).Child("_ByCusID").Child(Cusid + “.elf”)

if i use this code without children i get no errors and the app runs fine.
InvoiceFolder = New FolderItem(AppFolder.NativePath + “/Invoice/Data/estimate/_ByCusID/” + Cusid + “.elf”)

I’ve been trying to stick to strictly to programming with FolderItems and Children… i wanted to get away from the older style paths

How can i do this with FolderItems and children when a file does not exisit.??

Don’t string them together like that. If you’re not sure the path exists, use one Child call at a time and test them.

InvoiceFolder = AppFolder.Child("xxx")
if InvoiceFolder <> Nil and InvoiceFolder.Exists then InvoiceFolder = InvoiceFolder.Child("Data")
if InvoiceFolder <> Nil and InvoiceFolder.Exists then InvoiceFolder = InvoiceFolder.Child("estimate")
if InvoiceFolder <> Nil and InvoiceFolder.Exists then InvoiceFolder = InvoiceFolder.Child("_ByCusID")
if InvoiceFolder <> Nil and InvoiceFolder.Exists then InvoiceFolder = InvoiceFolder.Child(Cusid + ".elf")
if InvoiceFolder <> Nil and InvoiceFolder.Exists then
   // use it

Or write a helper method using Paramarray to hide the ugliness.

so with each test your testing than adding a child.

so i would make a function and pass each of the children as strings
inside the function test them as what you did in the ugliness ?

i think i got it.

using this method
InvoiceFolder = New FolderItem(AppFolder.NativePath + “/xxx/Data/xxxx/_ByCusID/” + Cusid + “.elf”)

does the folderitem convert “/” to “” and vise versa depending on the OS the app is running on?

The answer to your question is no, it does not.
However, do not do that either. Do it as the other Tim had said.

Hello Guys So I wanted to know
if the following routine looks good does if follow what Tim was doing ?
It runs, no errors, no exceptions, but it returns Nil when the file does exist.

Sub DoesFolderFileExist(Root As FolderItem, PathToFile As String)
Dim f As FolderItem = New FolderItem(Root.NativePath,  FolderItem.PathTypeNative)
Dim Folders() As String = Split(PathToFile, If(TargetWindows, "\", "/"))

If Folders(0) = "" Then
End If

For i As Integer = 0 To Folders.Ubound
  f = f.Child(Folders(i))
  if f <> Nil and f.Exists Then
    Return Nil
  End If

// Return Usable Folder
Return f
End Sub

This line is not needed, since you already have Root as a folderitem. It’s the equivalent of

Dim f as FolderItem = Root

But a lot more convoluted.

I would write it as

Function DoesFolderFileExist(Root as FolderItem, ParamArray Folders() as String) As FolderItem

Call it as

f = DoesFolderFileExist(AppFolder, "Data", "estimate", "_byCusID", cusid+".elf")
if f <> Nil and f.Exists then ...

Forget about splitting paths and delimiters. With Xojo, you really should never need to construct a path.

You could also do this, which is more compact:

try InvoiceFolder = AppFolder.Child("xxx").Child("Data").Child("xxx").Child("_ByCusID").Child(Cusid + ".elf") catch noe as NilObjectException ' does not exist end if InvoiceFolder <> nil and InvoiceFolder.Exists then ... you can probably access it unless it's locked or something end

@Tim Hare 's method lends itself to being able to tell you which level was missing though.

Right, if that’s what you need to know :slight_smile: Wasn’t in the OP’s requirements, though. I just added it because it’s the easiest solution to write, usually, and it wasn’t mentioned here. Programmers need to understand how to deal with Exceptions and not think “their program crashed” every time that happens.

Thank you for the advise on Exceptions, That seems more compact and easier to debug.
I will incorporate that in to my routine

TIm that’s right you did say use a ParamArray which looks even better and easier

Thank you

You’re welcome. As a general rule with FolderItems, keep these rules in mind:

• You’ll get nil if the parent directory to a path does not exist.
• You’ll get a non-nil FolderItem object if the parent item does exist. In that case, you can then check with Exists if that item (file or folder= inside the parent directory exists.

So, if you dive into a deeper folder structure using chained Child calls, like you did originally (and which is the best method in regards to being portable to Windows vs. Mac/Linux, for instance), it’ll go like this:


Assuming AppFolder exists as a folder, then child(“a”) will always be non-nil, and child(“b”) will be nil if “a” does not exist (or is a file instead of a folder), at which point access to child(“c”) would lead to the NilObjectException.

That’s why, if you get a Child’s result, you should always consider two possible conditions:
a) the result is nil
b) result.Exists may be true or false. (You don’t have to check for that explicitly if you’re just trying to open a file at that point - it’ll simply fail with an IOException if it doesn’t exist, then).


Ok Thomas i understand fully
Thank you

and now i will present the full solution that all of you have helped with
in case other progamers may want the code here it is
it works great !! and is easy to debug…


rtnFolder = DoesFolderFileExist(StartFolder, "folder1", "folder2", "folder3", "File" ..... )


sub DoesFolderFileExist(Root As FolderItem,  ParamArray Folders() as String) As FolderItem

For i As Integer = 0 To Folders.Ubound
  Root = Root.Child(Folders(i))
  if Root <> Nil and Root.Exists Then
    Return Nil
  End If

// Return Usable Folder
Return Root
End Sub

I like the use of ParamArray.

I would not call Exists in the loop, as that’s unnecessary - the next iteration would find that out automatically, by giving you nil, and only at the end, past the loop, I’d call Exists and return nil in that case. But that’s merely an optimization in your need-case.

That change would fix one little flaw in your code, though: If you expect to ALWAYS get nil if the folder does not exist, it would give you the false impression if you’d only pass the startFolder. Because then you’d not go into the loop and return the startFolder, even if that does not exist.

However, I’d rather rename the function “ConcatenatePath” and return a non-nil FolderItem at the end in case I want to check the existence myself after calling this function.

Also, your function name is misleading - it suggests that it returns a boolean.

Oh, and the loop could save a line if you did this with the “For …” and the next line:

For Each Root in Folders

Not nitpicking, just trying to help you learn a few tricks.

Actually, the documentation says you can’t rely on the order of a for each

Well, Tim, if you really believe that nonsense, then don’t use for each.

And before you want to argue:

It would be stupendously stupid to iterate over an array in any other way than forward. There’s no reason to do so on a machine code level, either. CPUs, especially those by Intel, are nowadays designed to support compilers, not vice versa. And since no other language would suddenly get such an idea with their own “for each” loop constructs, there’s no reason why Intel would suddenly invent some weird way to make reverse loops faster. And even then, no other language would suddenly change their behavior.

So, why would Xojo? To annoy us? I don’t think so.

I’m just pointing out what the documentation says. Because of the way the old docs had it worded I always use for i as integer when I need to be absolutely positive the order is correct.

Regularly, we have people here complaining that events do not happen in the order they expect. Yet, Xojo very clearly says it can change. And it does indeed, noticeably between platforms.

I did observe that for each usually are sequential from zero to ubound. But after all, if not random, it may very well be that for each goes from top to bottom for some reason on one platform one of these days.

Then I would tend to take the prudent approach, and take Xojo’s warning seriously.

Thomas Tempelmann
i think i’ll stick the "for i’ unless order does not matter.

Thomas Tempelmann
so your saying that Exisits is not needed inside the loop but would be more effective outside the loop?
something like the following.

For i As Integer = 0 To Folders.Ubound
  Root = Root.Child(Folders(i))
  if Root <> Nil Then
    Return Nil
  End If

if not Root.Exists then
    return Nil
end if

// Return Usable Folder
Return Root
End Sub