13.9. File and Alias
A file object is a reference to a file or folder on disk. To construct one, use an object string specifier the word file followed by a string representing a colon-delimited pathname:
By "colon-delimited" I mean an old-style Macintosh -type path. This is not the same as the new-style Unix-type path (new to Mac users, anyway), also known as a POSIX path. AppleScript has a long history on Macintosh, so it is not surprising that its native representation of file paths is not the Unix representation. Macintosh paths start with a disk name, and the delimiter between the disk name, folder names, and filename is a colon. A pathname ending in a colon is a folder or a disk. (A partial pathname, one whose first element is not a disk, is taken to start inside the "current directory," but the interpretation of this notion is unreliable, and partial pathnames should be avoided.)
Oddly, you can't assign a file object specifier to a variable, or return it as a value. If you try, you get a runtime error message:
set x to file "feathers:Users:mattneub:" -- error: Can't make file "feathers:Users:mattneub:" into type reference
Instead, you must generate a reference to the file object, like this:
set x to a reference to file "feathers:Users:mattneub:" x -- file "feathers:Users:mattneub:" of «script»
A file specifier is not resolved until the script actually runs. This means that the item on disk need not exist at compile time. At runtime, however, when the file specifier is handed to some command, either the item must exist, or, if the command proposes to create it, everything in the path must exist except for the last element, the name of the item you're about to create. Otherwise the command will generate a runtime error on the grounds that it can't find or create the item. We've already met one command that accepts a file specifier to create a filestore script (see "Compiled Script Files as Script Objects" in Chapter 8).
An alias object is very much like a file object. You can form an alias specifier in just the same way as you form a file specifier, and an alias object can often be used in the same places where a file object would be used. But there are some important differences:
Alias objects are commonly used by scriptable applications as a way of returning a pointer to an item on disk. For example:
tell application "BBEdit" get file of window 1 -- alias "feathers:Users:mattneub:someFile" end tell
In that code, the term file is merely the name of a window property, and has nothing to do with the file class from the previous section. (Well, almost nothing. Its raw four-letter code is the same as that of the file class. See Chapter 20.)
There is a longstanding confusion in AppleScript about how to specify the file to which a new document is to be saved. The dictionaries of many applications, such as GraphicConverter and TextEdit, say that the save command takes an alias. But this is impossible, because an alias must exist in order to speak of it, and clearly it doesn't, as what you're trying to do is create it. Because the dictionary is lying, you must experiment in order to find out what the application really wants. For example:
tell application "GraphicConverter" set s to "feathers:Users:mattneub:Desktop:joconde" save window 1 in alias s as PICT -- error: File feathers:Users:mattneub:Desktop:joconde wasn't found end tell
That code fails because the file doesn't exist. If you write the same code using a file specifier, there is a different mysterious error:
tell application "GraphicConverter" set s to "feathers:Users:mattneub:Desktop:joconde" save window 1 in file s as PICT -- error: GraphicConverter got an error: Can't get window 1. Access not allowed end tell
After a great deal of banging around, you finally try this, and it works:
tell application "GraphicConverter" set s to "feathers:Users:mattneub:Desktop:joconde" save window 1 in s as PICT end tell
It turns out that what GraphicConverter wanted was a pathname. Indeed, some newer applications' dictionaries explicitly ask for Unicode text, implying that they expect a pathname. Even then you're not home free, because there are two forms of pathname string. Only experimentation will reveal whether an application wants a Macintosh (colon-delimited) path or a POSIX-type path here.
13.9.2. Other File Classes
You can specify a file using a POSIX-type path, where the delimiters are slashes and an initial slash means the top level of the startup disk. To do so, use an object string specifier for a POSIX file instead of a file. If the path is a literal string, or if you ask to see a POSIX file as a result, AppleScript presents it as a file specifier with the delimiters changed to colons. So, for example, if I write this:
POSIX file "/Users/mattneub/"
AppleScript changes it to this at compile time:
The really weird part is that, despite appearances, this is not the same thing as a file object specifier! There are two ways to know this. First, it describes itself as a different class: it says it's a «class furl», which I take to be a file URL . Second, unlike a file specifier, a file URL can be assigned directly to a variable.
To see how insane this situation is, start with this (uncompiled):
set x to POSIX file "/Users/mattneub" set y to file "feathers:Users:mattneub"
When you run that, you get this:
set x to file "feathers:Users:mattneub" set y to file "feathers:Users:mattneub" -- error: Can't make file "feathers:Users:mattneub" into type reference
The two lines look identical, but the first line is a file URL. AppleScript complains only about the second line, which is a file object specifier. But now if you deliberately compile the script and run it again, look what happens:
set x to file "feathers:Users:mattneub" -- error: Can't make file "feathers:Users:mattneub" into type reference set y to file "feathers:Users:mattneub"
The file URL in the first line has been turned into a file object specifier, and now AppleScript complains about the first line! You can avoid a lot of this madness by using a variable instead of a literal in your specifier:
set s1 to "/Users/mattneub" set x to POSIX file s1 set s2 to "feathers:Users:mattneub" set y to a reference to file s2
The string used to form a file URL specifier must not contain a colon. If it does, various bad things can happen, depending on the version of AppleScript and the environment: an incorrect pathname might be generated (a bug in AppleScript), or the script could fail to compile or to run (silently, in the Tiger version of Script Editora bug in Script Editor).
The string used to form a file URL specifier need not denote an existing path:
set s to "/alice/in/wonderland" POSIX file s -- file "feathers:alice:in:wonderland"
You may regard this as a bug, but in any case, don't use such a string in the first place. Similarly, don't form a file URL specifier with a string that does not start with a slash; partial pathnames are unreliable.
The file URL class pops up in various contexts, lurking behind the file class. For example, the choose file name scripting addition is documented as returning a file object, and appears to do so, but in reality it's a file URL.
A few old applications still expect or generate a deprecated, outmoded class called file specification (class 'fss '). For example:
tell application "BBEdit" set r to check syntax file "feathers:Users:mattneub:Desktop:testing.html" class of result_file of item 1 of r -- file specification end tell
You can even form a file specification object using an object string specifier, but don't. They can behave oddly; that's why they are deprecated. The file class replaces the file specification class transparently. So stick to a file object and let the transparency work for you.
13.9.3. File Properties
The following is a property of a file, an alias, or a file URL:
That is the only file property, but there are some scripting addition commands (see Chapter 21) that supplement the file classes in valuable ways. For example, you can obtain a host of useful information about a file, such as its creation date, whether it's invisible, whether it's a folder, how big it is, what application opens it, and lots of other cool stuff, with the info for command:
info for file "feathers:Users:mattneub:someFile"
The result comes back as a record, which is easy to read and well documented in the StandardAdditions dictionary, so I won't go into details here. You can also obtain a list of the names of a folder's contents with the list folder command. There are also commands for reading and writing a file, and there's even some interface for letting the user choose a file.
13.9.4. File Classes in Applications
Don't confuse the AppleScript file object with the file class as defined by a particular scriptable application. For example, the Finder defines a file class, but it's a completely different file class. One way you can tell this is that, on the one hand, it has no POSIX path property, and on the other hand, it has lots of elements and properties not defined in AppleScript itself. For example:
tell application "Finder" get owner of file "feathers:Users:mattneub:myFile" -- mattneub end tell
You couldn't do that without the Finder, because the owner property is defined by the Finder. It's true that the second line appears to contain a file object specifier, but it doesn't. Rather, this is a name element specifier, just like saying folder "Mannie". It just so happens that the Finder lets you use a pathname as the "name" for many of its classes.
Another way to see that the Finder's file class is not AppleScript's file class is to try handing an AppleScript file object to the Finder. You can't do it:
set f to a reference to file "feathers:Users:mattneub:myFile" tell application "Finder" get owner of f -- error: Can't make «class sown» of file "feathers:Users:mattneub:myFile" into type reference end tell
What that error tells you is that you're not even targeting the Finder. The variable f is a file object reference belonging to your script, not an object in the Finder at all.
Similarly, the Finder's alias file class is not an alias object.