bynkii (bynkii) wrote,
bynkii
bynkii

Adventures in creating new files to save

Before we get into today's bit:
  1. File URLs are not File Paths

  2. 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

  3. Documentation that interchanges terms like "path" and "url" makes me want to go all stabbity-stabbity

  4. 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_(theDataFilePath, 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_(theDataFileURL, 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:completionHandler: 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!
Subscribe
  • Post a new comment

    Error

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

    When you submit the form an invisible reCAPTCHA check will be performed.
    You must follow the Privacy Policy and Google Terms of use.
  • 0 comments