"open for access" error in modern AppleScript

EDIT: The answer to this question was that I needed to put all this into a tell application “Finder” block… Years and years ago, I had in fact had this part of the code inside a Finder block, but someone told me that this wasn’t necessary - and in fact it was not necessary until I added the new header to the code. So ignore all this…

'm updating a script that I’ve used for many years, because I want to add Shane Stanley’s superb applescript for creating a PDF from a file. That routine requires the lines

use scripting additions
use framework "Foundation"
use framework "AppKit"

But when I add these to my script, this routine produces an error message on the first line:

set fRef to (open for access file (checkItem as text)) -- Open the file just once 
try
	set hasFileHeader to (((read fRef for 4 as data) is «data rdatFF575043»))
	set fileTypeByte to (read fRef from 10 for 1 as data)
	set versionByte to (read fRef from 11 for 1 as data)
	set cryptByte to (read fRef from 13 for 1 as data)
on error
	display dialog "Program error. Couldn't read the file." with title msgTitle buttons {"OK"} giving up after 10
end try
close access fRef -- Close the file again.

The error when I try to open the file for access is:

Can’t make current application into type «class fsrf».

Is there an equivalent of “open for access” that I can still use to read specified bytes from the file?

Answered my own question in an edit to the original. Sorry for bandwidth-wasting…

you can just use the read command without open for access. That’s required if you want to write to the file, or want other apps to see it as busy.

The following works only if it has the “use script additions” command. (Are you sure that’s in there?)

Open for access, read and write are all scripting addition commands.


use scripting additions
use framework "Foundation"
use framework "AppKit"
set fRef to alias "Macintosh HD:Users:user:Desktop:06-15-18-Fri-Daily TV Grid:Fri_STD.TXT"
set hasFileHeader to (read fRef for 4 as data)
set fileTypeByte to (read fRef from 10 for 1 as data)
set versionByte to (read fRef from 11 for 1 as data)
set cryptByte to (read fRef from 13 for 1 as data)
 

Ed, that works. Thank you. I seem to have been making beginners’ errors about files and aliases that didn’t have any effect until I tried to update the script. Apologies for wasting bandwidth, and thanks again.

That’s not a good answer — scripting addition commands should generally not be within application tell blocks.

The real problem is that when you include a use framework statement, AppleScript behaves a bit differently with the file specifiers file and alias.

There are a couple of workarounds. The first, and the one I prefer, is to use «class furl» instead if file. So your script would be:

set fRef to (open for access (checkItem as text) as «class furl») -- Open the file just once 

You can also use a tell block like this:

tell current application
    set fRef to (open for access file (checkItem as text)) -- Open the file just once 
end tell

In the case of alias, you can get around the issue by using somePath as alias rather than alias somePath.

1 Like

Yes - I realized that when Ed Stockley answered. I had got myself muddled in two different ways. As Ed says, I can use the code that he suggested and all’s well.

What is completely new to me is what you say about frameworks and using «class furl». This will be a big help in the future. Thank you again.

Actually, to be pedantic, ‘open for access’ isn’t required for writing either. It’s simply a specialised access opening tool which creates a file if it doesn’t exist, opens an access channel to it with or without write permission, and returns a reference number for the specific channel opened. Using this reference ensures that ‘read’, ‘write’, and the other commands all use the same, already open channel, saving time and possible confusion when multiple Read/Write actions are performed on the same file.

If any of the other File Read/Write commands is passed a file or an alias instead of an access reference, it’ll first attempt to use an existing access channel to the file. If none are open, it’ll open its own with the necessary permissions, carry out its task, and close the channel again afterwards. So if a file exists and isn’t already open for access, it’s possible to write to it too without explicitly getting write permission access first:

set theFile to ((path to desktop as text) & "Aardvark.txt") as «class furl»

-- Create the file if it doesn't exist.
close access (open for access theFile)

-- If no access channel currently exists to the file, open one with write permission, write to it, and close it again afterwards.
-- Otherwise, if a channel with write permission already exists and there are no others open, use the existing channel and leave it open.
-- Otherwise, if channel(s) already exist and none has write permission, attempt to use one and get an error.
-- Otherwise, if channels already exist and one of them has write permission, attempt to use one and hope it's the right one.
write "Hello world!" to theFile as «class utf8»

-- If no access channel currently exists to the file, open one, read the file from the beginning, and close the channel.
-- Otherwise, if channel(s) already exist to the file, use one and attempt to read the file from the channel's current file mark.
read theFile as «class utf8»

Or even more pedantically, the first-opened file handle to the file — there can be more than one.

Thanks, Shane. :man_student: :wink:

For example:

set thePath to POSIX path of ((path to desktop as text) & "Silly test.txt")
set x to open for access thePath
set y to open for access thePath with write permission
write "some text" to y as «class utf8»
write "some more text" to thePath as «class utf8» -- throws: File not open with write permission.
close access x
close access y