- File URLs are not File Paths
- Just because NSFileHandle can deal with URLs, that doesn't mean NSFileManager does. So you can use either a path or a URL to create a handle to an existing file, but to create the file itself, you have to use the path
- Documentation that interchanges terms like "path" and "url" makes me want to go all stabbity-stabbity
- Knowing when NOT to use "my" is important too
Now, on to today's bit.
I've been spending most of my time of late dealing with the "Cocoa" way to save and open files. Now, there's no functional reason to do this, AppleScript has had some solid ways to do this for some time now in Standard Additions. So, if you want to create a new file, open a write handle to it, write some data to it, then close the file handle, you have:
set theFile to choose file name with prompt "enter a new file name to be created, or choose a new file that will be obliterated" default name "newfile.txt"
set theFileHandle to open for access theFile write permission true
write aBigBunchOfData to theFileHandle
close access theFileHandle
It's pretty straightforward. Choose File name lets you 'choose' a file that may not exist yet. We then use Open For Access with write permission to get a handle to the file that we can use for writing data. Write then shoves data into the file handle, and close access closes off the file handle. If you pick an existing file, any data in that file is obliterated. (We'll deal with appending data later.)
Doing this in AppleScriptObjC, at least the "Cocoa" way is a bit more involved, but worth digging into, as a teaching exercise alone.
So, here's the code block I have for creating a new file. Note that I'm not yet actually writing data into it, just getting everything ready to do so:
on createNewFile_(sender) --create a new file
set theSavePanel to my NSSavePanel's savePanel() --create the save panel object
theSavePanel's setMessage_("Create New Data File")
theSavePanel's setAllowedFileTypes_(theFileTypeArray)
--we want to be specific here, and only allow certain types, in our case, text
theSavePanel's setExtensionHidden_(0)
--in the AppleScriptObjC is not objectiveC file: for bools, use 1 or 0 not YES or NO
--if you don't, you'll get fussed at and you'll never know why
theSavePanel's setAllowsOtherFileTypes_(1)
--yes we only want text, but we don't want to be dicks about it.
--if someone really wants something else, sure.
--if someone really wants to use .dat or whatever, fine, they can
theSavePanel's |setNameFieldStringValue_|("WiFi Analyzer Data.txt")
--i named this as STringValue once and AppleScript being, well
--AppleScript, it will hang on to that forever! so the pipes around it help me deal with that
set theSavePanelResult to theSavePanel's runModal()
--display the panel and get the binary result
if theSavePanelResult is 1 then
--if they clicked the 'save' button, then we want to get the path and set some flags
set theDataFileURL to theSavePanel's |URL|()
--get the encoded URL, which is not the file path, but we'll need it
set theDataFilePath to theSavePanel's filename()
set createDataFile to true
--we're creating a new data file, so this has to be true
set appendToExisting to false
--we are not appending data, so set to false
set theFileManager to my NSFileManager's defaultManager()
--create a file manager object so that we can create a blank file
set theCreateFileResults to theFileManager's createFileAtPath_contents_attributes_(th eDataFilePath, missing value, missing value)
--creates a blank file at the path specified.
--Do NOT use "my theFileManager's..." because errors will happen
set theFileHandle to my NSFileHandle's fileHandleForWritingToURL_error_(theData FileURL, missing value)
--use this to write to the file URL
--you could probably also use fileHandleForWritingToPath here,
--but since URLs are the way of the future
--we should use them where we can
log theFileHandle
theFileHandle's closeFile() --we'll use this later
end if
end createNewFile_
I left the comments in, as they do a decent job of explaining each statement. One thing I learned is that Cocoa is big on "create the object, THEN do stuff to it" whereas traditional AppleScript lets you avoid the create the object. For example, you don't have to create a file manager object, so that you can use that to create a new blank file, which then lets you get the file handle to it so that you can write data to it. With AppleScript, you just get the file path for the new file, get the handle, write, and go.
This also follows with the save panel. You create the save panel, configure the save panel, then actually run the save panel so it displays. (Also, if anyone has some sample ASOC code for
beginSheetModalForWindow:completionHandl er:
or beginWithCompletionHandler:
and wanted to post it in the comments or link to where it is, I'd not cry.)Next in line...actually writing data, and then appending data to the end of an existing file. Woohoo!