Shell vs. Absolute vs. Native... Which is best?

Hello all! Another dumb question from yours truly.

I’ve written an application that shows a list of recent files, saved in a preferences file. I noticed a little issue today: when I try to open/access one of the recent files, if the FOLDER in which the file has been removed or deleted, Xojo throws an “Unsupported Format” exception. However, if the folder exists but the file doesn’t, it behaves correctly.

Which leads me to my question. I’ve been using “PathTypeShell”, but am thinking that I need to use “PathTypeAbsolute” (which does not throw an exception). Clearly, I just don’t understand the difference between the HFS path and the POSIX path.

Does anyone mind giving a brief summary of the difference, and confirm that the “Absolute” is indeed what I should use? Should I use it across my project, or there instances where I should use one vs. the other?

Thank you!!

//Suppose fname is the path of a file that no longer exists, nor does its containing folder 'f = new folderitem(fname, FolderItem.PathTypeShell) // Throws "Unsupported Format" exception 'f = new folderitem(fname, FolderItem.PathTypeNative) // Also throws "Unsupported Format" exception f = new folderitem(fname, FolderItem.PathTypeAbsolute) // Works correctly if f.Exists = false then

Asking this question in 3 different postings will not get a faster response, will not change the answer if you do get one, and may cause people to ignore you all together

Dave, I’m VERY sorry, but I didn’t mean to; I’ve deleted the other postings. The page froze and gave me an error message saying that I should try pressing “post a reply” again… so I did.

(I’m not sure why it posted in the “Customer Service” forum, either… It said “OS X” on the top of the posting!)

[quote=210277:@Matthew Pool]Hello all! Another dumb question from yours truly.

I’ve written an application that shows a list of recent files, saved in a preferences file. I noticed a little issue today: when I try to open/access one of the recent files, if the FOLDER in which the file has been removed or deleted, Xojo throws an “Unsupported Format” exception. However, if the folder exists but the file doesn’t, it behaves correctly.

Which leads me to my question. I’ve been using “PathTypeShell”, but am thinking that I need to use “PathTypeAbsolute” (which does not throw an exception). Clearly, I just don’t understand the difference between the HFS path and the POSIX path.

Does anyone mind giving a brief summary of the difference, and confirm that the “Absolute” is indeed what I should use? Should I use it across my project, or there instances where I should use one vs. the other?

Thank you!!

//Suppose fname is the path of a file that no longer exists, nor does its containing folder 'f = new folderitem(fname, FolderItem.PathTypeShell) // Throws "Unsupported Format" exception 'f = new folderitem(fname, FolderItem.PathTypeNative) // Also throws "Unsupported Format" exception f = new folderitem(fname, FolderItem.PathTypeAbsolute) // Works correctly if f.Exists = false then[/quote]

Would you be so kind to post the exact content of the string fname ? That would greatly help explaining the errors.

Thanks for your response, Michel! The variable fname is based on the list of recent files, so it changes depending on the file chosen.

In this case, fname was set to “/users/matthewjpool/desktop/shows/32-funnythingforum_cast.smtdx”. (As you can see- no spaces or awkward characters).

The problem is raised after I deleted the folder “shows” and its contents, and then tried to open the file. When I use PathTypeAbsolute, Xojo is happy. When I use PathTypeShell, Xojo raises the “Unsupported Format” exception.

So… I’m wondering… What is the difference, and should I change all the instances of “Shell” to “Absolute” in my project?

I should also add… If the file was on the desktop and deleted (such as “/users/matthewjpool/desktop/32-funnythingforum_cast.smtdx”), Xojo does not raise this exception and behaves normally, even when “Shell” is used.

I’ve deduced that this must have something to do with the existence of the folder that contains the file, and you can’t delete the desktop.

If you’re attempting to save these paths, you shouldn’t use any of these. Use the GetSaveInfo method of the FolderItem and restore it with new FolderItem( theSaveInfo ). If the target has moved or even changed names, this technique should still find it.

Kem, very good to know! I will have to play around with that and implement that when I get back to my computer later.

In that case… When (if ever) would you specify the path of a FolderItem in the constructor?

You generally shouldn’t. If you can, start from one of the SpecialFolder items and use Child to get to the item you want. For example:

dim f as FolderItem = SpecialFolder.Desktop.Child( "MyFile" )

Having said that, many (including me) will use a path as a shortcut from time to time. In those cases, it doesn’t really matter which version of the path you use as long as you know which type it is. I generally use NativePath.

But if that path points to items in folders that don’t exist, you will have issues. Likewise, if you use Child on a FolderItem that doesn’t exist, you will have issues. You need to code defensively if that’s a possibility.

IMO, you can only test exists on the last member of the path, not when a higher member on the branch has been deleted.

I do not think what happens with NativePath is right. At any rate, an invalid path should trigger an exception. Using the constructor triggers an UnsupportedFormat, and using GetFolderItem triggers a NilObjectException.

You should know that it is indeed a non existing path before testing the existence of the last member (“32-funnythingforum_cast.smtdx”). I would then tend to use GetFolderItem to make sure and a Try-Catch structure.

Kem did not mention the main reason why GetSaveInfo should be used : in case the path contains spaces, they will be escaped. As he wisely advises, code defensively, rather than rely on a method that lets a blatant error go through silently.

OK! Thank you all for your helpful info about this. It really clears some confusion up. As I mentioned elsewhere, most of my background is working in Windows, which to the best of my knowledge, is not as flexible in this regard.

I’ve spent some time this morning trying to rewrite the code in my project to use GetSaveInfo and GetFolderItem for my list of recent files.

It seems that I can save the GetSaveInfo information, but I can’t retrieve it properly. I created a sandbox program to test, but it doesn’t seem to work: (Download on Dropbox)

I’m trying to save the GetSaveInfo info using TextOutputStream, but I’m wondering if this changes the encoding and looses some of the info?

[code] dim s as string
s = p_file.GetSaveInfo(nil, 0)

Dim f As FolderItem = SpecialFolder.Desktop.Child(“folderitemtest.pref”)
Dim t As TextOutputStream
try
t = TextOutputStream.Create(f)
t.WriteLine(s)
msgbox “Success!”
catch
msgbox “Error writing file!”
end try
t.Close[/code]

Try a binary stream
SaveInfo is NOT text

OK. I think I’ve got it now. I ran into a couple of other bumps in the road. What a massive headache.

Norman is correct: GetSaveInfo (etc) apparently only works when saved as a binary stream. I guess “string” is more broad than “text”.

I’ve been using JSON to store the preferences into a file. Except, I was using [JSONItem].ToString, which doesn’t work even when saving as a binary stream.

//DOESN'T WORK!! Dim data As String = mPreferences.ToString Dim stream As BinaryStream stream = BinaryStream.Create(mPreferencesFile, True) // Overwrite if exists stream.Write(data) stream.Close

Now I have to write each bit of the preferences file manually. Kindof messy, and considerably more complicated than the other way, but at least it works.

[code]//Recent files are saved in p_recentfiles folderitem array
//mRecentFiles is the JSONitem

Dim stream as BinaryStream
stream = BinaryStream.Create(mPreferencesFile, True)
stream.Write("{" + endofline)
dim names() as string = mPreferences.Names
for i as integer = 0 to names.Ubound
stream.write(" “”" + names(i) + “”":""")

If i < p_recentfiles.ubound then
if p_recentfiles(i) <> nil then
stream.write(p_recentfiles(i).getsaveinfo(nil, 0))
else
stream.write(“nil”)
end if
else
stream.write(mPreferences.Value(i).StringValue)
End If

stream.write("""")
if i <> mPreferences.names.ubound then
stream.write("," + endofline)
End If

Next

stream.write(endofline+ “}”)
stream.close[/code]

bangs head against wall repeatedly while sobbing

Hex encode it before storing to json.

“string” is a kind of misleading name
It CAN be textual data - with an associated encoding so it is handled as utf-8 or whatever encoding
And it can also be “bucket of bytes” with no encoding associated with it
This dual nature causes no end of confusion

[quote=210455:@Matthew Pool]I’ve been using JSON to store the preferences into a file. Except, I was using [JSONItem].ToString, which doesn’t work even when saving as a binary stream.

//DOESN'T WORK!! Dim data As String = mPreferences.ToString Dim stream As BinaryStream stream = BinaryStream.Create(mPreferencesFile, True) // Overwrite if exists stream.Write(data) stream.Close
[/quote]
Doesn’t work in what way ?
If you open the file after writing it in a text editor I’d put money on the data is there unless there was an error creating the file (which you dont check for)

How you open & read the file is also relevant since you would need to read this & turn it back into a json item
But cant comment on how you do that since there’s no code

Ah yeah and kems probably right about hex encoding the save info - it probably contains characters like NUL’s etc that are not “text” or something that can be safely put in json

Oh my gosh. You guys are lifesavers. Encoding/decoding hex works PERFECTLY.

[quote=210457:@Norman Palardy]Doesn’t work in what way ?
If you open the file after writing it in a text editor I’d put money on the data is there unless there was an error creating the file (which you dont check for)

How you open & read the file is also relevant since you would need to read this & turn it back into a json item
But cant comment on how you do that since there’s no code[/quote]

You’re right: the data is saved, and can be retrieved, but something happens to it between using the “ToString” function, saving, and retrieving that causes it to change enough that GetFolderItem doesn’t accept it. But it does work when the string has been converted to hex.

Woo!! Thank you so much!

Nulls aren’t a problem because they are valid Unicode. The problem will be in byte sequences that don’t represent valid UTF-8.