Open text files from App Rescource + insert text into document

Some months ago I did a smaller version of this but hard coded the insert text. This time with the project so much larger with so much more text it was only practical to open a choice of documents from the application resource and use that for inserting into a document onto the person’s computer. My problem is although it does actually insert the text, it also inserts a map of where the insert source came from at the beginning of the insertion. The document the text will be inserted into is a simple plain text document however uses a .props file extension. Do I need to specify some kind of Unicode command or something?

Also, I received an error about one of the files not being open. Here’s the script:

set new_name to "W"
set theDestinationFolder2 to .
set thisSource to path to resource "K.props"
set search_text to "BLACK="
set insert_text to path to resource "Block1.txt"
set insert_text2 to path to resource "Block2.txt"
set insert_textB to path to resource "Block1B.txt"
set insert_text2B to path to resource "Block2B.txt"
set the_file to (path to ...
set ref_num to (open for access the_file with write permission)

tell application "Finder"
	try
		set f to (((path to preferences folder from user domain) as Unicode text) & new_name) as alias
	on error
		set theDestinationFolder2 to (path to preferences folder from user domain)
		set theDestinationFolder2 to ((theDestinationFolder2 as text) & "W:") as alias
		set f to {make new folder at (path to preferences folder from user domain) with properties {name:"W"}} as alias -- creates folder if does not exist
		duplicate thisSource to theDestinationFolder2 -- copies a props file across if one does not already exist
	end try
	
	display dialog ".." buttons {"A", "B", "Cancel"} default button "B"
	set response to button returned of the result
	
	if response is "B" then -- inserts text either after 'BlACK=' or adds it to end of document.
		try
			set the_text to (read ref_num) -- eof error if no text 
			-- find the byte 
			set the_offset to (offset of search_text in the_text)
			if (the_offset = 0) then error "Search string wasn't found."
			set byte_after to (the_offset + (length of search_text))
			try
				set trail_text to (text byte_after thru -1 of the_text)
			on error -- there is no trailing text 
				set trail_text to ""
			end try
			open insert_text
			write (insert_text & trail_text) to ref_num starting at byte_after
			close access ref_num
			close insert_text
		on error
			close access ref_num

			set thePath to (path to preferences folder from user domain) & "W:K.props" as text
			set fRef to (open for access file thePath with write permission)
			try
				open insert_textB
				insert_textB
				-- Start writing from the end of the file.
				write to fRef starting at eof
				close insert_textB
			end try
			close access fRef
			set theData to (read file thePath)
		end try
		
	else if response is "A" then -- Same as response B but different data to be inserted.
		try
			set the_text to (read ref_num) -- eof error if no text 
			-- find the byte 
			set the_offset to (offset of search_text in the_text)
			if (the_offset = 0) then error "Search string wasn't found."
			set byte_after to (the_offset + (length of search_text))
			try
				set trail_text to (text byte_after thru -1 of the_text)
			on error -- there is no trailing text 
				set trail_text to ""
			end try
			open insert_text2
			write (insert_text2 & trail_text) to ref_num starting at byte_after
			close access ref_num
			close insert_text2
		on error
			close access ref_num
			
			set thePath to (path to preferences folder from user domain) & "W:K.props" as text
			set fRef to (open for access file thePath with write permission)
			try
				open insert_text2B
				insert_text2B
				-- Start writing from the end of the file.
				write to fRef starting at eof
				close insert_text2B
			end try
			close access fRef
			set theData to (read file thePath)
		end try
	end if
	
	display alert "... "... as critical buttons {"Quit"} default button "Quit" ... set response to button returned of the result
	
end tell
quit

Here is the applescript error message:

This is the bonus text that was inserted at the beginning:
BLACK=listalis HDD Name (Lots of strange characters)
Resources HDD Name: Applescript installer work:MacOSX - WWW installer.app:Contents:Resources:Block1.txt

I’ve tried a variation, such as
copy insert_text to clipboard
write (clipboard & trail_text) …

But this still inserts unwanted characters at the beginning.
Perhaps my search techniques for answers to topic on the forum were not good. I was unable to find an appropriate technique for achieving the objective.

Hi,

no offense, but your read/write code looks a bit confusing.
You have to take care that the open/close pairs are balanced

First of all, reduce the Finder tell block to the lines which contain Finder terminology,
actually the creation of the folder and the copying of the source file.

I’d recommend to use a handler to manage open, write and close in one scope,
something like this, it closes the file reference reliably and returns a boolean value for success or failure


on writeToDisk(theFile, theData, theStartingPoint)
	-- theFile can be HFS path or alias
	-- theData contains the text to write
	-- theStartingPoint is the byte position, if missing value start at eof
	try
		set fileRef to open for access file (theFile as text) with write permission
		if theStartingPoint is missing value then
			write theData to fileRef starting at eof
		else
			write theData to fileRef starting at theStartingPoint
		end if
		close access fileRef
		return true
	on error
		try
			close access file (theFile as text)
		end try
		return false
	end try
end writeToDisk

I don’t understand these lines at all


open insert_text2B
insert_text2B

the open line tell the Finder to open a file but doesn’t read any contents
the second line does nothing.

If you want to get the contents of a .txt file use the read command.
It doesn’t require a file reference created by open for access

Thanks StefanK, not sure I could hope for a better person to answer my question. :smiley: You seem to have a certain expertise with applescript that stands out.

I tried the Read command and worked perfectly immediately. I’ll see how I can clean up the rest of the script now using your suggestion. Thanks again. :slight_smile:

I am still in the novice basket. Perhaps if I were writing scripts constantly I might get past that stage.

It’s been quite a while since this thread I guess. But I was unable to get it to work for me and gave up.
In the meantime I discovered a different and more efficient way of achieving the end result by adding a separate file and adding a reference to it in a program’s props (settings) file. So when the program opens its props file points the program to read a particular file within its prefs folder.

So all I need to do is insert one line of text. Ideally the script would check to be sure it’s not already there but that’s not important at this time. :lol:

I can not even get this script to write to the file no matter how much I try to simplify it.

I tried your script in similar fashion but same results. The script just won’t write to the file for some reason, even if write to file is all I have in the script.

set this_data to "PATH_TO_.... /LimeWire/H.txt" & return
set target_file to (path to preferences folder from user domain) & "limewire:limewire.props" as text

on write_to_file(this_data, target_file, append_data)
	try
		set the target_file to the target_file as string
		set the open_target_file to open for access file target_file with write permission
		if append_data is false then set eof of the open_target_file to 0
		write this_data to the open_target_file starting at eof
		close access the open_target_file
		return true
	on error
		try
			close access file target_file
		end try
		return false
	end try
end write_to_file

My other script did at least write to the file but now I do not wish it to insert after a particular word but simply insert a line of text onto a fresh line. EOF is fine though a few lines down from top of the text file would be ideal. This is probably so simple, but I just cannot seem to get it to work. I know I’m dumb. Sorry if I sound a little frustrated.

I’m not sure if I should have defined append data but I did try that. I’m not sure if append data is what I am after anyway.

Edit:
Here is a simplified version, result is always false.

set target_file to (path to preferences folder from user domain) & "limewire:Hostiles.txt" as text
try
	set the open_target_file to open for access file target_file with write permission
	writeToFile(("PATH_TO_.../LimeWire/H.txt" as string) & return, target_file, false)
	close access the open_target_file
on error
	try
		close access target_file
	end try
	return false
end try

Why is the result always false no matter how I try to tweak the script?

write_to_file is a subroutine, so you have to call it and pass the respetive parameters


set theText to "PATH_TO_.... /LimeWire/H.txt" & return
set theFile to (path to preferences folder from user domain as text) & "limewire:limewire.props"
write_to_file(theText, theFile, false)

on write_to_file(this_data, target_file, append_data)
	try
		set the target_file to the target_file as string
		set the open_target_file to open for access file target_file with write permission
		if append_data is false then set eof of the open_target_file to 0
		write this_data to the open_target_file starting at eof
		close access the open_target_file
		return true
	on error
		try
			close access file target_file
		end try
		return false
	end try
end write_to_file

Thanks that works but just one issue, the script totally overwrites the props file with just that one line of text. What can be done to just insert/write that line of text at the end of the props file?

Also, when I replaced my previous portions of script in the main script program with the above script, the script did not like the On write_to_file(this_data, target_file, append_data) saying it did not like the “On” word and was instead looking for “else”.

The set theText to “PATH_TO_… /LimeWire/H.txt” & return is at start of script. The set theFile is in the IF section because the user may not have such a location at beginning of the script.

if exists file "limewire.props" of theDestinationFolder2 then --- checks to see if the user already has a props file.
				set theFile to (path to preferences folder from user domain as text) & "limewire:limewire.props"
				write_to_file(theText, theFile, false)
				
				on write_to_file(this_data, target_file, append_data)
...

So I removed the “On” word and the “end write_to_file” but the script installer fails saying …

write_to_file("PATH_TO_B.../LimeWire/H.txt

", “OSX:Users:me:Library:Preferences:limewire:limewire.props”, false)
→ error number -1708
error “Finder got an error: Can’t continue write_to_file.” number -1708

a handler (on .) must be placed at the top level of the script, so put it at the end of the main code.
If you want to append data, just set the append_data flag to true.
Inside an application tell block put the keyword my in front of the handler call

Funny attribute but realised what you meant eventually after some duplicate functions were skipped over. All is working as it should be on all fronts. A big thank you again. :smiley:

A fine-tune might be to search the props file to see if the text line already exists first, but one day I might figure that one out. No luck so far. I’ll ship the application as is for now. Thanks again. :slight_smile:

I may ask you for one more piece of advice on how to search the props file to see if the text already exists before writing to it. :confused: ie: setting up a condition. I finally feel I am so close but just cannot get it to work.

I had been wanting to try to solve this myself. After researching other posts here and other internet articles and checking samples on computer, etc. I had been unable to solve this.

I ended up reverting to my original approach from a few months ago for testing. That way works.

set search_text to "PATH_TO_ . Preferences/LimeWire/H.txt"
set insert_text to "PATH_TO_ . Preferences/LimeWire/H.txt"
set the_file to (path to preferences folder from user domain) & "limewire:limewire.props" as text
set ref_num to (open for access the_file with write permission)
try
	set the_text to (read ref_num) -- eof error if no text 
	-- find the byte 
	set the_offset to (offset of search_text in the_text)
	if (the_offset = 0) then error "Search string wasn't found."
	close access ref_num
on error
	close access ref_num
	set thePath to (path to preferences folder from user domain) & "limewire:limewire.props" as text
	set fRef to (open for access file thePath with write permission)
	try
		-- Start writing from the end of the file.
		write "PATH_TO_ . Preferences/LimeWire/H.txt" to fRef starting at eof
	end try
	close access fRef
end try

But by attempting to adjust the recent code with a similar approach to the above does not work: (no errors, just does not write to the file.) I thought this would be one way of setting up the condition to only write to file if the search text does not already exist.

if exists file "limewire.props" of theDestinationFolder2 then --- checks to see if the user already has a props file.
					set theFile to (path to preferences folder from user domain as text) & "limewire:limewire.props"
					
					try		
						set the target_file to the target_file as string
						set the open_target_file to open for access file target_file with write permission
						set the_text to (read target_file) -- eof error if no text 
						-- find the byte 
						set the_offset to (offset of search_text in the_text)
						
						if append_data is false and (the_offset = 0) then set eof of the open_target_file to 0
						write this_data to the open_target_file starting at eof
						close access the open_target_file
						return true
					on error
						try
							close access file target_file
						end try
						return false
					end try

maybe there’s a problem with the reference theDestinationFolder2

Hi lotr.

Your script in post #1 and subsequent changes are a bit of a mess and it’s difficult to be sure exactly what’s intended. You’re also apparently not understanding the few clues Stefan’s tossing to you.

Could you please confirm, correct, or expand upon the following analysis of your aims?

¢ The script’ will be saved and run as an application or as a script bundle.
¢ ‘thisSource’, ‘insert_text’, 'insert_text’2, ‘insert_textB’, and ‘insert_text2B’ are text files within the script’s bundle.
¢ There should be a folder in the user’s Preferences folder called “W” and this should contain a copy of ‘thisSource’ (aka a file called “K.props”). If they’re not there, create them.
¢ The script will have input parameters in the form of a path or an alias to a text file which isn’t any of the above and some text which may or may not exist in it.
¢ The user will be offered an informative choice of actions: “A” or “B”.
¢ If the user chooses “B” and the parameter text occurs in the parameter file, insert the text from the ‘insert_text’ resource file at that point in the parameter file.
¢ If the user chooses “B” and the parameter text does not occur in the parameter file, append the text from the ‘insert_textB’ resource file to the end of the “K.props” file in folder “W”.
¢ If the user chooses “A” and the parameter text occurs in the parameter file, insert the text from the ‘insert_text2’ resource file at that point in the parameter file.
¢ If the user chooses “A” and the parameter text does not occur in the parameter file, append the text from the ‘insert_text2B’ resource file to the end of the “K.props” file in folder “W”.
¢ One of your later posts mentions “insert a line”. Is this just for the “K.props” insertions or both or what? What kind of line endings do you want? Line feeds or returns?

Edit: PS.
¢ What kind of text is in the files? Mac Roman, UTF-8 Unicode, or UTF-16 Unicode? If the last, is it big-endian or little-endian?

The script’ will be saved and run as an application bundle. It includes a basic props file for those installing LimeWire for the first time. This includes word and file-extension filters and a link to the path to the H.txt file.

The bundle also includes a connection file, and 4 versions of the H.txt file depending on user choice. BTW H.txt stands for Hostiles.txt :smiley:

The insert a line option is for those persons whom already have the program installed and already have a props file (the main program settings file.)

I wanted to provide periodic updates to the H. file so people could run an updated installer, but not have multiple entries of the text line specifying the path to the H. file.

For people installing LimeWire for the first time, they first use this installer. It installs the basics of the program settings (preferences files.) The installer first checks to see if they already have such a preferences folder (in case they had used the program in some time past.) If the folder does not exist the installer creates the folder, then installs the files mentioned above.

The installer’s initial menu has 3 options, Light or strong or no security (this will only install the connection file.) Choice of either of the first two options leads to 2 other variations of the security file. After completion there’s a finale menu just to specify the process has finished and if questions to click on the link to the forum.

I will be packaging this installer with each version of the LimeWire version 4 and 5 installers, including a LimeStart script I created earlier in the year which will prevent LimeWire deleting its connection file if it has not been used in previous 30 days. 3 installers within each LW installer package numbered in sequence of use.

This http://macscripter.net/viewtopic.php?id=39735 is the first half of each of the options the user has. This thread’s scripting represents the second half of each of the options. The script represents what a single option would have. Simply to make it easier to review/discuss to break it down since each option’s coding is identical with the exception of one.

I was about to reply to StefanK with . Maybe it’s my logic lol. I realised the first example is writing upon an error. I guess the not finding of the search text generates an error, thus goes to the error step which simply closes the props file’s write access.

I tried so many different kinds of search/replace approaches but I was not skilful enough to make them work in with this code.

At your suggestion two things I can think of: an issue with the destination folder and or the handler. I did experiment with trying to add a search to the handler.
I set the Destination2 location directly after the … on write_to_file(this_data, target_file, append_data) … which is near the start of the script (after the folder exists check and folder creation.)

set theDestinationFolder2 to (path to preferences folder from user domain)
set theDestinationFolder2 to ((theDestinationFolder2 as text) & "LimeWire:") as alias

Then the display menu follows this. So the Destination2 location is specified at same level as the main menu and each of the 3 main menu choices.

Oops just saw your edit. What kind of text, it’s just plain text, not Rich Text. How do I find out?
MS-Word queries me which encoding to open it with, but that might be due to the unknown file extension.
Open Office suggests UTF-8 when opening.

Using this technique http://codeftw.blogspot.com.au/2009/07/how-to-find-character-encoding-of-text.html According to FireFox the text encoding is Western (ISO-8859-1). Most similar files are UTF-8 according to Windows Detenc

Hmmm. Well I think this comes close to fixing the problems with the script at the top of this thread. It’s too much in one afternoon to unravel the entire thread and another one! :wink:

I’ve gone with UTF-8 text and linefeeds. (Change ‘as «class utf8»’ to ‘as string’ if it turns out to be ISO-8859 after all.) A single handler called ‘security_setup’, with appropriate parameters, handles the similar actions for choices “A” and “B”. I’m still not clear if ‘search_text’ and ‘the_file’ are supposed to be hard_wired or input as parameters, but that should be easy for you to sort out. Hope this helps.

on main()
	set new_name to "W"
	set thisSource to (path to resource "K.props")
	set search_text to "BLACK="
	set insert_text to (path to resource "Block1.txt")
	set insert_text2 to (path to resource "Block2.txt")
	set insert_textB to (path to resource "Block1B.txt")
	set insert_text2B to (path to resource "Block2B.txt")
	--set the_file to (path to ...
	
	set Path_to_prefs to (path to preferences folder from user domain as Unicode text)
	tell application "Finder"
		try
			set theDestinationFolder2 to (folder (Path_to_prefs & new_name)) as alias
		on error
			set theDestinationFolder2 to (make new folder at folder Path_to_prefs with properties {name:new_name}) as alias -- creates folder if does not exist
			duplicate thisSource to theDestinationFolder2 -- copies a props file across
		end try
	end tell
	
	display dialog ".." buttons {"A", "B", "Cancel"} default button "B"
	set response to button returned of the result
	
	if (response is "B") then -- inserts text either after the search text or adds it to end of document.
		security_setup(the_file, search_text, insert_text, insert_textB, theDestinationFolder2)
	else if (response is "A") then
		security_setup(the_file, search_text, insert_text2, insert_text2B, theDestinationFolder2)
	else
		-- "No security" option here, but you won't have enough buttons in the 'display dialog' above.
	end if
end main

-- Handle the security preferences for choice "A" or "B".
on security_setup(the_file, search_text, insert_file, insertB_file, theDestinationFolder2)
	set fRef to (open for access the_file with write permission)
	try
		set the_text to (read fRef as «class utf8») -- eof error if no text 
		if (the_text does not contain search_text) then error "Search string wasn't found."
		
		-- If the text in the_file contains the search text, insert the text from insert_file after that point and write the entire text back to the_file. We don't want to risk writing from individual file bytes with Unicode text.
		set text_to_insert to (read insert_file as «class utf8»)
		set astid to AppleScript's text item delimiters
		set AppleScript's text item delimiters to search_text
		set TIs to the_text's text items
		set AppleScript's text item delimiters to search_text & text_to_insert
		set new_text to TIs as text
		set AppleScript's text item delimiters to astid
		
		set eof fRef to 0
		write new_text as «class utf8» to fRef
		close access fRef
	on error
		close access fRef
		
		set text_to_insert to (read insertB_file as «class utf8»)
		set thePath to (theDestinationFolder2 as text) & "K.props"
		set fRef to (open for access file thePath with write permission)
		try
			-- Start writing from the end of the file, with a linefeed first if there's something already in it.
			if ((get eof fRef) > 0) then write linefeed as «class utf8» to fRef starting at eof
			write text_to_insert to fRef starting at eof
		end try
		close access fRef
		set theData to (read file thePath) -- This needs to be returned to the main handler or acted on here.
	end try
end security_setup

Thanks. Sorry for late reply. Whilst I no longer needed to read contents of files in the resource folder, I highly appreciate the lesson because no doubt I will use that approach in future. Though it did not work when I tried to adapt it. np

I decided to go with what I had with StefanK’s idea and ideas from the other thread. Thanks for the help.

Applescript does not like insert character
I have another similar project but different program. Objective is to insert a line or two of text. But applescript does not like a colon within the text to insert. So I tried an adapted version of Nigel’s method of reading from a file within resource folder (but without the search function), but the script does not do anything lol. No events/results happening at all.

The text to insert = “Security.FilteredPorts[L:0]=”

Applescript ‘does not understand’ the : character. I tried placing inside [ ] but still no good. it seems the slash \ before the colon : is what causes the issue.

Any trick to dealing with this?
I would have thought ‘anything’ within the inverted commas would be read as text. I tried putting as «class TEXT» at the end, but then errors with anything else within inverted commas later on in the script.

Model: 2008 macpro
AppleScript: 2.3
Browser: Firefox 16.0.2
Operating System: Mac OS X (10.6)

That’s right. The backslash is used for quoting certain characters – \r for return, \n for linefeed, \t to tab. To use it in text like that you need to add a second backslash.

Thanks for the quick reply and help. :slight_smile: That did the trick!