File Macintosh HD:path:output.txt is already open. (-49) ?

My script saves a file and can be run multiple times in one session. After the process is done the user is prompted to save the output text (containing the STDOUT output of the cli program I’m wrapping).

If a file by that name already exists, the user is prompted on whether they wish to overwrite the file. If they select “Ok” this error is thrown for a file of name output.txt:

File Macintosh HD:USERS:jkyle:Desktop:output.txt is already open. (-49)

Here is the pertinant code:

on saveOutput(theOutput)
	set thePath to choose file name with prompt "Save Output to File" default name "output.txt"
	set theFileID to open for access thePath with write permission
	write (theOutput as text) & return to theFileID
	close theFileID
end saveOutput

Where theOutput is just a text string. As you can see, I do close the file.

Further, the error is produced across sessions of the program. So I can Quit, recompile, save output, and get the same error.

And last, the file does not have to be created by the program (thought the close theFileID might not be working). I can go to Terminal.app and touch path/to/file/output.txt then run my program and try to overwrite it…still same error.

I’ve also checked to make sure that the output.txt was indeed left untouched/unoverwritten to ensure that it was not in fact overwriting it and the error came from some later, overlooked process.

You should try and close the file if an error occurs (which may have happened earlier):

on saveOutput(theOutput)
	choose file name with prompt "Save Output to File" default name "output.txt"
	try
		set theFileID to open for access (result) with write permission
		write (theOutput as text) & return to theFileID
		close theFileID
	on error errMsg number errNum
		try
			close theFileID
		end try
		
		error errMsg number errNum
	end try
end saveOutput

This is not valid code:

Building target “ImageConvertor” of project “ImageConvertor” with configuration “Release” ” (1 error)
cd /Users/jkyle/Projects/Cocoa/ImageConvertor
/usr/bin/osacompile -d -i /System/Library/Frameworks/AppleScriptKit.framework -U ImageConvertor.applescript -x -o /Users/jkyle/Projects/Cocoa/ImageConvertor/build/Release/ImageConvertor.app/Contents/Resources/Scripts/ImageConvertor.scpt /Users/jkyle/Projects/Cocoa/ImageConvertor/ImageConvertor.applescript
/Users/jkyle/Projects/Cocoa/ImageConvertor/ImageConvertor.applescript:255: Expected “end” but found “on”. (-2741)
/Users/jkyle/Projects/Cocoa/ImageConvertor/ImageConvertor.applescript:255: Expected “end” but found “on”. (-2741)
/Users/jkyle/Projects/Cocoa/ImageConvertor/ImageConvertor.applescript:255: Expected “end” but found “on”. (-2741)
Build failed (1 error)

Can’t nest two on blocks. Is there another way to do it?

You can’t have a handler inside a handler, but a try block is not handler. Let’s see the rest of your code (specifically, a few lines before line 255).

Sure thing, this is my first applescript so it’s probably pretty nasty. Haven’t updated the header info yet either…but here you go. You’ll fiind the saveOutput function toward the bottom:

-- ImageConvertor.applescript
-- ImageConvertor

-- DESCRIPTION
--	Simple gui wrapper for mri_convert (part of the freesurfer suite).

--	Expected Input: 
--                            Either a Directory or a File to be converted
--                            As well as any non-required options desired

--	Expected Output for Directory Input: 
--                             A series of image files of specified $type 
--                             for each DICOM series found in $directory and 
--                             $subdirectories

--	Functions: 
--		saveOutput(string theOutput)
--			Expected Input: String
--			Expected Output: TextEdit document with content = string theOutput
--			Description: Is passed a $string holding the output of mri_convert
--                                     Pass $string to TextEdit which creates a new document
--                                     with property text set to $string

--		getExtensions(string TYPE)
--			Expected Input: String containing value of inputType or outputType
--			Expected Output: string containing extension expected by mri_convert

--  Created by James Kyle on 6/29/06.
--  Copyright 2006 UCLA Brainmapping Center. All rights reserved.
--

property panelWindow : missing value
global mriWrapper
global inputFile
global outputFile
global itemInfo
global FREESURFERHOME
global OPTS
global extKey
global browseButton

on awake from nib
	set mriWrapper to (resource path of main bundle) & "/mriWrapper.pl"
	
	set ASTID to AppleScript's text item delimiters
	set AppleScript's text item delimiters to {" "}
	set textItems to text items of mriWrapper
	set AppleScript's text item delimiters to {"\\ "}
	set mriWrapper to textItems as string
	set AppleScript's text item delimiters to ASTID
	
	set FREESURFERHOME to (resource path of main bundle) & "/freesurfer"
	set extKey to title of current cell of matrix "outputType" of drawer "drawer" of window "main"
	set OPTS to ""
end awake from nib

on launched theObject
end launched

on choose menu item theObject
	
	if (the name of theObject) is equal to "openFile" then
		selectInput()
		
	else if (the name of theObject) is equal to "preferences" then
		display alert "This feature has not been enabled as of yet."
		(*	if panelWindow is equal to missing value then
			load nib "SettingsPanel"
			set panelWindow to window "settings"
			display panelWindow
		end if
		
		tell panelWindow 
		end tell *)
	end if
end choose menu item

on clicked theObject
	if (the name of theObject) = "selectExt" then
		tell window "main"
			tell drawer "drawer"
				set currentState to state of it
				
				if currentState is in {drawer opened, drawer opening} then
					close drawer
				else if currentState is in {drawer closed, drawer closing} then
					open drawer on bottom edge
				end if
				
			end tell
		end tell
		
	else if (the name of theObject) = "convert" then
		set outputFile to contents of text field "outputFile" of window "main"
		if (kind of itemInfo) is "Folder" then
			set OPTS to OPTS & "-ot:" & (title of current cell of matrix ¬
				"outputType" of drawer "drawer" of window "main") & ":"
			
			set outputFileRef to POSIX file outputFile
			set folderName to (do shell script "date '+%H-%M-%S'")
			set folderName to "Results-" & folderName
			
			tell application "Finder"
				make new folder at outputFileRef with properties {name:folderName}
			end tell
			
			set outputFile to outputFile & folderName
		end if
		
		set commandString to mriWrapper & " '" & (resource path of main bundle) & "/Libs' " & ¬
			" -in " & "'" & inputFile & "'" & ¬
			" -out " & "'" & outputFile & "'" & ¬
			" -fh " & "'" & FREESURFERHOME & "'"
		
		if ((kind of itemInfo) is "Folder") then
			set commandString to commandString & " -oe " & getExtension(extKey)
			set Type to " -type directory"
			
		else if ((kind of itemInfo) is not "Folder") then
			set Type to " -type file"
		end if
		
		set commandString to commandString & Type
		
		if (OPTS is not equal to "") then
			set commandString to commandString & " -opts " & "'" & OPTS & "'"
		end if
		
		with timeout of 3600 seconds
			set theOutput to (do shell script commandString & " 2>&1")
		end timeout
		saveOutput(theOutput)
		
		set outputFile to ""
		set OPTS to ""
		
	else if (the name of theObject) is equal to "outputType" then
		set extKey to title of current cell of matrix "outputType" of drawer "drawer" of window "main"
		
		if ((kind of itemInfo) is not equal to "Folder") then
			my setOutputExtension()
		end if
		
	else if (the name of theObject) is equal to "apply" then
		
	else if (the name of theObject) is equal to "inputBrowse" then
		selectInput()
		
	else if (the name of theObject) is equal to "outputBrowse" then
		selectOutputDirectory()
	end if
	
end clicked

on panel ended theObject with result withResult
	if withResult is 1 then
		if browseButton is equal to "input" then
			set inputFile to ""
			set itemInfo to ""
			set inputFile to (item 1 of (path names of open panel as list))
			set itemInfo to info for (POSIX file inputFile)
			
			set ASTID to AppleScript's text item delimiters
			set AppleScript's text item delimiters to {"/"}
			set theFileParent to (text items 1 thru -2 of inputFile) as string
			set AppleScript's text item delimiters to ASTID
			
			tell window "main"
				set contents of text field "inputFile" to inputFile
				
				if (kind of itemInfo) is "Folder" then
					set contents of text field "outputFile" to theFileParent & "/"
					set visible of text field "message" to true
					show
					
				else
					set contents of text field "outputFile" to theFileParent & "/out." & my getExtension(extKey)
					set visible of text field "message" to false
					show
				end if
			end tell
			
			set browseButton to ""
			
		else if browseButton is equal to "output" then
			set outputDirectory to ""
			
			set outputDirectory to (item 1 of (path names of open panel as list)) & "/"
			tell window "main"
				if ((kind of itemInfo) is not equal to "Folder") then
					set outputDirectory to outputDirectory & "out." & my getExtension(extKey)
				end if
				
				set contents of text field "outputFile" to outputDirectory
			end tell
			set browseButton to ""
			
		end if
		
	end if
	
end panel ended

on setOutputExtension()
	set outputName to contents of text field "outputFile" of window "main"
	
	set ASTID to AppleScript's text item delimiters
	set AppleScript's text item delimiters to {"/"}
	
	set rootFile to (text item -1 of outputName) as string
	set filePath to (text items 1 thru -2 of outputName) as string
	
	if rootFile is equal to "" then
		display alert "You must provide a file name"
	else
		set AppleScript's text item delimiters to {"."}
		if ((count of text items of rootFile) > 1) then
			if ((text item -2 of rootFile) is equal to "nii" and (count of text items of rootFile) > 2) then
				set fileName to ((text items 1 thru -3 of rootFile) as string) & "." & getExtension(extKey)
			else
				set fileName to ((text items 1 thru -2 of rootFile) as string) & "." & getExtension(extKey)
			end if
			
		else
			set fileName to rootFile & "." & getExtension(extKey)
		end if
		
		set contents of text field "outputFile" of window "main" to filePath & "/" & fileName
		
	end if
	set AppleScript's text item delimiters to ASTID
end setOutputExtension

on getExtension(Type)
	set extMap to ¬
		{"cor", "cor", ¬
			"mgh", "mgh", ¬
			"mgz", "mgz", ¬
			"minc", "mnc", ¬
			"analyze", "img", ¬
			"analyze4d", "img", ¬
			"spm", "img", ¬
			"afni", "brik", ¬
			"bshort", "bshort", ¬
			"bfloat", "bfloat", ¬
			"outline", "mgh", ¬
			"gdf", "gdf", ¬
			"nifti1", "img", ¬
			"nii.gz", "nii.gz"}
	
	set i to 1
	
	repeat until (item i of extMap) is equal to Type
		set i to i + 1
	end repeat
	
	return (item (i + 1) of extMap)
end getExtension

on saveOutput(theOutput)
	choose file name with prompt "Save Output to File" default name "output.txt"
	try
		set theFileID to open for access (result) with write permission
		write (theOutput as text) & return to theFileID
		close theFileID
	on error errMsg number errNum
		try
			close theFileID
		end try
		
		error errMsg number errNum
	end try
end saveOutput

on selectInput()
	set can choose directories of open panel to true
	set can choose files of open panel to true
	set browseButton to "input"
	display open panel in directory (system attribute "HOME") attached to window "main"
end selectInput

on selectOutputDirectory()
	set browseButton to "output"
	set can choose directories of open panel to true
	set can choose files of open panel to false
	
	display open panel in directory (system attribute "HOME") attached to window "main"
	
	
	
end selectOutputDirectory

You’ll notice a shell script is called, it’s a perl script I wrote as a wrapper to mri_convert.

K, bumping this back to the top.

So, I’m still getting the save file error. Even using the try code block suggested.

It appears that this is the process erroring out on the second save attempt:

set theFileID to open for access (result) with write permission

So, here’s the issue:

  1. This completes with zero errors on first attemp:

    choose file name with prompt “Save Output to File” default name “output.txt”
    try
    set theFileID to open for access (result) with write permission
    write (theOutput as text) & return to theFileID
    close theFileID

Then on second attempt this call errors out with "File Macintosh HD:path:output.txt (-49):

	set theFileID to open for access (result) with write permission

So the catch all to prevent the problem here:

on error errMsg number errNum
	try
		close theFileID

Is never being called since the first is not initially throwing an error, even though it is not closing the file.

Is there not some way to simply test if a file is open? So:

choose file
if (file is open) close file
open file for writing

In your second attempt, what is ‘result’? It certainly isn’t whatever it was before, and after closing a file, fileID is discarded as well.

Why are you opening and closing the file if you want to write more than once? Just leave it open. If you want to overwrite it, then ‘set eof of fileID to 0’ will accomplish that. If you leave the eof where it was, the second write to the file will append to it. Further, you don’t need a try block to span the whole thing. With each attempt to write to it, you enclose that in a try that will close it if the write doesn’t succeed and displays a dialog of the error that caused it


-- stuff happens
set fid to open for access ((path to desktop as text) & "myFile.txt") with write permission
try
	set eof of fid to 0
	write ("This is the first entry" & return) to fid -- just a sample
on error e
	close access fid
	display dialog e
	return -- quit; something is screwed up
end try
--- do more stuff; file should still be open, fid still ok if you got here
try -- leaving eof where it was
	write "This is the second entry" & return to fid -- second line
on error e
	close access fid
	display dialog e
	return -- bag it
end try
-- continue with stuff
close access fid