A universal write_to_file routine

I expanded the routine which was published once to be able
to write selectively text, UTF8 and UTF16 data to a file with AppleScript’s Standard OSAX

set myTestfile to ((path to desktop) as string) & "write_to_file_test"

write_to_file from "Hallo World" into myTestfile by 3 without append -- parameter notes: target=path string; textClass 1=text, 2=UTF8, 3=UTF16

on write_to_file from |data| into target by textClass given append:append
	script t
		property textClassList : {string, «class utf8», Unicode text}
	end script
	try
		set datastream to open for access file target with write permission
		if append is false then set eof of datastream to 0
		-- write BOM if text class is Unicode text
		if (get eof of datastream) = 0 and textClass = 3 then write (ASCII character 254) & (ASCII character 255) to datastream
		write |data| to datastream as (item textClass of t's textClassList) starting at eof
		close access datastream
		return true
	on error
		try
			close access file target
		end try
		return false
	end try
end write_to_file

I’ve added this to my script library recently (it’s based on yours, Stefan):

(* `writeFile` parameters
	---------------------
		someData	[anything]	The data to be written.
		someFile	[mixed]		The file to write to; Must be an alias, file, or text.
		textClass	[class]		The class the data should be saved as; Should be either Unicode text, «class utf8», or string.
		bom			[bool]		Add a BOM to new or overwritten files for Unicode text or  «class utf8».
		append		[bool]		Add to the existing data or overwrite it?
*)

on writeFile from someData into someFile given class:textClass, bom:includingBOM, append:append
	try
		tell (someFile's class) to if it is not file or it is not alias then set someFile to file specification someFile
		open for access someFile with write permission
		set fileRef to result
		
		if not append then set eof of fileRef to 0
		if includingBOM and ((get eof of fileRef) is 0) then
			if textClass is Unicode text then write (ASCII character 254) & (ASCII character 255) to fileRef
			if textClass is «class utf8» then write (ASCII character 239) & (ASCII character 187) & (ASCII character 191) to fileRef
		end if
		
		write someData to fileRef as textClass starting at eof
		close access fileRef
		return true
	on error errMsg number errNum
		try
			close access fileRef
		end try
		
		--error errMsg number errNum
		return false
	end try
end writeFile

Edit: Example usage:

set theFolder to (path to home folder as Unicode text)
writeFile from "Hello, World!" into (theFolder & "Test UTF-8.txt") without bom and append given class:«class utf8»
writeFile from "Hello, World!" into (theFolder & "Test UTF-8 BOM.txt") with bom without append given class:«class utf8»
writeFile from "Hello, World!" into (theFolder & "Test UTF-16.txt") with bom without append given class:Unicode text
writeFile from "Hello, World!" into (theFolder & "Test String.txt") without bom and append given class:string

very neat :slight_smile:

Oops, forgot to include the example statements.

Hi, Stefan and Bruce.

Nice handlers! Interestingly, although it’s still necessary to specify ‘as Unicode text’ or 'as «class utf8» when reading the files with the File Read/Write ‘read’ command, the BOMs are recognised for what they are and aren’t included in the result.

More for interest than for any great improvement, here are a couple of alternative ways to write the BOMs, in case they appeal to you:

if includingBOM and ((get eof of fileRef) is 0) then
	if textClass is Unicode text then write -257 as short to fileRef -- Short integer with hex value FEFF
	if textClass is «class utf8» then write -272908544 for 3 to fileRef -- First 3 bytes of integer with hex value EFBBBF00!
end if

Or:

if includingBOM and ((get eof of fileRef) is 0) then
	if textClass is Unicode text then write «data rdatFEFF» to fileRef
	if textClass is «class utf8» then write «data rdatEFBBBF» to fileRef
end if

Thanks for the BOM note, Nigel. Also, I like that «data» method.

Ugh! :mad::lol:

Pun not intended. :wink:

Another alternative: [Edited]

writeFile:

-- someData  : Data (anything) to be written
-- someFile  : File to write to; An alias, file, file specification, or text is expected
-- dataClass : Class the data should be written as (e.g. text, Unicode text, or «class utf8»)
-- appending : Should new data be appended to existing data?
--
on writeFile for someData into someFile given class:dataClass, appending:appending
	try
		if class of someFile is not in {alias, file, file specification} then ¬
			set someFile to file specification someFile
		
		open for access someFile with write permission
		set fileRef to result
		
		if not appending then set eof of fileRef to 0
		if appending and dataClass is Unicode text then write «data rdatFEFF» to fileRef
		
		write someData to fileRef as dataClass starting at eof
		close access fileRef
	on error errMsg number errNum
		try
			close access fileRef
		end try
		
		error errMsg number errNum
	end try
end writeFile

writeTempFile:

-- someData  : Data (anything) to be written
-- dataClass : Class the data should be written as
--
on writeTempFile for someData given class:dataClass
	try
		do shell script "/usr/bin/mktemp -t writeTempFile"
		set tempFile to result as POSIX file
		
		open for access tempFile with write permission
		set fileRef to result
		
		if dataClass is Unicode text then write «data rdatFEFF» to fileRef
		
		write someData to fileRef as dataClass starting at 0
		close access fileRef
		
		return tempFile as alias
	on error errMsg number errNum
		try
			close access fileRef
		end try
		
		error errMsg number errNum
	end try
end writeTempFile

I like it, Bruce, it’s becoming better and better :slight_smile:

Oy. I really should have learned to read the whole thread before posting by now! Oh well, I’ll leave it here.

I have a similar bit of code. Perhaps it’s interesting to you.

set parameters to {theData:{"hello"}, toFile:"titan:Users:paulskin:Desktop:bob"}
WriteData(parameters)


on WriteData(parameters)
	set previousTIDs to AppleScript's text item delimiters --Store the TIDs' initial value.
	try
		----------------SingleArgumentCore---------------
		set AppleScript's text item delimiters to ""
		try
			set theData to theData of parameters
		on error
			if class of parameters is string then
				set theData to parameters
			else
				WriteData()
			end if
		end try
		
		try
			set toFile to toFile of parameters
			tell application "Finder"
				if class of toFile is alias then set toFile to toFile as text
				if ((class of toFile) is document file) then set toFile to (toFile as alias) as text
			end tell
		on error
			try
				set toFile to ((path to desktop folder) as text) & (datetimeStamp of DateAndTime({}))
			on error
				set toFile to ((path to desktop folder) as text) & ((time of (current date)) as text)
			end try
		end try
		
		try
			set asClass to asClass of parameters
		on error
			set asClass to class of theData
		end try
		
		try
			set target to open for access file toFile with write permission
		on error
			
		end try
		try
			write theData to target as asClass
		on error
			
		end try
		try
			close access target
		on error
			
		end try
		return toFile
		--------------------------------------------------
		set AppleScript's text item delimiters to previousTIDs --Restore the TIDs to their initial value.
		return the output
	on error errorMessage number errorNumber partial result errorResult from errorFrom to ErrorTo
		set AppleScript's text item delimiters to "" --Modify unhandled errors to include the class and name of this object.
		set errorMessage to ("The " & (class of WriteData) & " '" & "WriteData" & "' generated an error." & return & the errorMessage) as text
		set AppleScript's text item delimiters to previousTIDs
		error errorMessage number errorNumber partial result errorResult from errorFrom to ErrorTo
	end try
end WriteData



--Documentation for WriteData. 
--These properties can be referenced for documentation and for version and dependency checking.
property name : "WriteData" --The name of this script object. <TEXT>
property objects : {WriteData} --A list of objects that are within this script object. <LIST>
property version : 1.0 --A version code for this object. <REAL>
property dependencies : {asDependencies:{}, osDependencies:{}, osaxDependencies:{}, handlerDependencies:{}, applicationDependencies:{}} --<RECORD>
property documentation : "WriteData Object.

	WriteData will write the passed data to a file. The file can be specified or allowed to default to the desktop. A name for the file can be specified or allowed to default to a Date & Time stamp.
	
	Parameters: STRING or 
	RECORD {theData:theData,toFile:toFile,asClass:asClass}
		theData: Anything.
		toFile: A file path, file reference or ALIAS.
		asClass: The class to try to write theData as.

	Output: An ALIAS to the written file.
	
	Error Handling: 	Errors that are not handled by WriteData internally will be modified to contain the name and class of WriteData before being thrown.

Paul Skinner 2002
paulskinner@mac.com
" --<TEXT>