How to open time-locked text file without error?

When a text file hasn’t been opened for a while, it is locked by OS X and any attempt at modifying it is greeted (in TextEdit) by a dialog box asking if we want to first unlock or duplicate the file. In Applescript this causes a problem that I haven’t found how to solve.

The file in question is a ChangeLog, to which I append a dated line every time some action occurs. If the file has been recently opened, the script does its job correctly. But if it’s time-locked (and Finder doesn’t show it as locked, BTW), then the script fails. See error after the code.


	set theFileReference to open for access theFilePath with write permission
	set logEntry to (((current date) as text) & " test writeLog" & return)
	write logEntry to theFileReference starting at eof
	close access theFileReference

From the bottom pane of the programming window:

tell current application
open for access “Macintosh HD:Users:afficheur:Afficheur:ChangeLog.txt” with write permission
Résultat :
error “Le fichier file Macintosh HD:Users:afficheur:Afficheur:ChangeLog.txt est déjà ouvert.” number -49 from file “Macintosh HD:Users:afficheur:Afficheur:ChangeLog.txt” to «class fsrf»

TRANSLATION: File … is already open.
NO, it isn’t; it only happens for a time-locked file, so the description is wrong. But the problem remains whole, how to open for access a time-locked file and be able to append to it? If I use TextEdit rather than Open for access, the error message is different but the result is the same.

Model: iMac 24"
AppleScript: 2.2.1
Browser: Safari 536.30.1
Operating System: Mac OS X (10.8)

Hi. Welcome to MacScripter.

I don’t know about time-locked files, but the error you’re getting does usually occur if the file’s already open for access. Either the script errored while an access was open during a previous run and stopped before it could execute the ‘close access’ command, or another process currently has ‘write permission’ access to the file.

You should protect the access with a ‘try’ statement while it’s open, so that if anything goes wrong, the script will keep going long enough to close the access. You should also use a proper ‘file’ or ‘alias’ specifier with the ‘open for access’ command, not just a path.


set theFileReference to (open for access file theFilePath with write permission) -- NB. 'file theFilePath'.
try -- Everything that happens while the file's open for access should be in a 'try' statement.
	set logEntry to (((current date) as text) & " test writeLog" & return)
	write logEntry to theFileReference starting at eof
end try
close access theFileReference

An easy way to close all a script’s orphaned accesses is to quit either the application running the script or whatever application it told to open the accesses. Otherwise you have to log out or write another script to close the accesses.

Thanks Nigel, you were right. Even though I didn’t see any evidence of it, the file was indeed open due to a previous failure to complete the script, perhaps as I had used TextEdit in an earlier version of the script. TextEdit draws a dialog sheet when attempting to open time-locked files, which blocks execution of the script.

I had to quit ScriptEditor to finally release the access on the text file.

In your suggested script, shouldn’t you have put the open command in the try block? After all, that’s the line that was causing problem. And it appears I’d better put the close in a try block as well, to avoid tripping the whole script if the file was not open in the first place.


	set logEntry to (((current date) as text) & " test writeLog" & return)
	try
		set theFileReference to open for access file theFilePath with write permission
		write logEntry to theFileReference starting at eof
	end try
	try
		close access theFileReference
	end try
        return logEntry

It wasn’t causing the problem. It was reacting to the problem caused in a previous run. :slight_smile:

Different people have different ways of arranging the ‘try’ block(s) here, depending on what they want to happen. The logic of my way is that the script will error and stop in the unlikely event of a problem occurring during ‘open for access’, since there’s no point in carrying on then anyway. The ‘theFileReference’ variable won’t be set and the file may be open from before or not open at all. If there’s no problem during ‘open for access’, the ‘close access’ command will definitely work as long as the script’s allowed to get that far.

On the other hand, many people do like to catch any error which may occur. If ‘open for access’ fails, it may be because there’s a ‘write permission’ access already open, as in your case. (You can open as many read-only accesses as you like, but a file can only have one ‘write permission’ access open at a time.) You can’t use the access reference to close the file in this case, since it wasn’t set. You have to use the file specifier:


set logEntry to (((current date) as text) & " test writeLog" & return)
try
	set theFileReference to (open for access file theFilePath with write permission)
	write logEntry to theFileReference starting at eof
	close access theFileReference -- Access reference.
on error errMsg
	try
		close access file theFilePath -- File specifier.
	end try
	display dialog errMsg
end try
return logEntry

Or perhaps (untested):


set logEntry to (((current date) as text) & " test writeLog" & return)
try
	set theFileReference to (open for access file theFilePath with write permission)
on error
	try
		close access file theFilePath
		set theFileReference to (open for access file theFilePath with write permission)
	end try
end try
try
	write logEntry to theFileReference starting at eof
	close access theFileReference
on error errMsg
	try
		close access file theFilePath
	end try
	display dialog errMsg
end try
return logEntry