In Cocoa you can use NSMutableData to append NSData chunks and then the writeToFile… / writeToURL… methods of NSData to write the data directly to disk. The NSFileHandle way is actually not needed in this case.
There are more roads which lead to Rome than in AppleScript
Just an example:
I was asking if there is a way to write the BOM
then write the text itself.
At this time you append the text to the BOM in ram them write the entire data in a single instruction.
As you pointed, this may be done with old fashioned AppleScript.
Yvan KOENIG running Sierra 10.12.3 in French (VALLAURIS, France) jeudi 16 mars 2017 10:54:14
They are not values but they are masks, who are the same. For instance the default unicode mask contains two encodings.
It’s not possible with text files in general so those methods won’t exist. That is where the power of binary files comes in with data blocks but that doesn’t work for NSData or NSString classes. For larger files you could also use streams to reduce the memory footprint.
Appending data to the NSData object could be resource heavy which makes a file handle (session write) much more efficient than concatenating data and write it as a whole to disk. From efficiency perspective a far better choice.
The mask is 0x100 the other bit is CF or NS identification but is not an encoding mask.
More specifically the NSENCODING_MASK is added to NSUTF16BigEndianStringEncoding which is 1<<31 value, note the starting 9. So while their value may not be the same, their masks are the same just what I said before.
The script in post #26 makes an NSMutableData version of the BOM and an NSData version of the text, appends the latter to the former, and writes the result to a new file with a single write.
The first script in post #37 appends the text to a character with the same Unicode value as the BOM, makes an NSData version of the result, and writes that to a new file with a single write.
The second script in post #37 makes NSData versions of both the BOM and the text, creates a new file, opens it for writing, writes the BOM data, then writes the text data, then closes the access.
The post #26 script’s probably the best of the three for the current purpose, since it does only do one write and also works in Mac OS 10.10. The other two are simply explorations of different approaches.
try
tell fileAccess to writeData:BOMData
tell fileAccess to writeData:stringData
set theResult to true
end try
is ASObjC code, not old fashioned code.
So now it seems that I understood.
If I made no error we may also use this 4th version:
# http://macscripter.net/viewtopic.php?id=28482&p=2
# message #26 alt
use AppleScript version "2.4"
use framework "Foundation"
use scripting additions
on modifyPath:thePath adding:addString
on modifyPath:thePath adding:addString
set pathString to current application's NSString's stringWithString:thePath
set theExtension to pathString's pathExtension()
set thePathNoExt to pathString's stringByDeletingPathExtension()
set newPath to (thePathNoExt's stringByAppendingString:addString)
if theExtension's |length|() > 0 then
set newPath to newPath's stringByAppendingPathExtension:theExtension
end if
return newPath as string
end modifyPath:adding:
on decodeFile:thePath
-- Get the BOM value as a two-character string. (The single character id (254 * 256 + 255) gets lost in the conversion to NSString.)
set theUTF16BEBOM to current application's NSString's stringWithString:(string id {254, 255})
-- Convert it to two bytes of data.
set BOMData to theUTF16BEBOM's dataUsingEncoding:(current application's NSISOLatin1StringEncoding)
-- Read the contents of the ISO Latin 1 text file.
set theString to current application's NSString's stringWithContentsOfFile:thePath encoding:(current application's NSISOLatin1StringEncoding) |error|:(missing value)
-- Convert that to data too, but encoded as UTF-16 big-endian, and append it to the BOM data.
set stringData to theString's dataUsingEncoding:(current application's NSUTF16BigEndianStringEncoding)
-- Write the lot to a new file.
set newPath to my modifyPath:thePath adding:"-new"
tell current application's NSFileManager's defaultManager() to createFileAtPath:newPath |contents|:(missing value) attributes:(missing value)
-- Open it for access with write permission, write the two blocks of data to it, and close it again.
set fileAccess to current application's NSFileHandle's fileHandleForWritingAtPath:newPath
try
tell fileAccess to writeData:BOMData
tell fileAccess to writeData:stringData
set theResult to true
end try
tell fileAccess to closeFile()
return {newPath, theResult as boolean}
end decodeFile:
set theSource to (choose file)
set {newPath, bof} to my decodeFile:(POSIX path of theSource)
Yvan KOENIG running Sierra 10.12.3 in French (VALLAURIS, France) jeudi 16 mars 2017 15:37:24
use AppleScript version "2.4"
use framework "Foundation"
use scripting additions
on modifyPath:thePath adding:addString
set pathString to current application's NSString's stringWithString:thePath
set theExtension to pathString's pathExtension()
set thePathNoExt to pathString's stringByDeletingPathExtension()
set newPath to (thePathNoExt's stringByAppendingString:addString)'s stringByAppendingPathExtension:theExtension
return newPath as string
end modifyPath:adding:
on decodeFile:thePath
-- Get the BOM value as a two-character string. (The single character id (254 * 256 + 255) gets lost in the conversion to NSString.)
set theUTF16BEBOM to current application's NSString's stringWithString:(string id {254, 255})
-- Convert it to two bytes of data.
set BOMData to theUTF16BEBOM's dataUsingEncoding:(current application's NSISOLatin1StringEncoding)
-- Read the contents of the ISO Latin 1 text file.
set theString to current application's NSString's stringWithContentsOfFile:thePath encoding:(current application's NSISOLatin1StringEncoding) |error|:(missing value)
-- Convert that to data too, but encoded as UTF-16 big-endian.
set stringData to theString's dataUsingEncoding:(current application's NSUTF16BigEndianStringEncoding)
-- Write the BOM data to a new file using the NSData method. If that works, open the file for access with write permission, move the file pointer to the end of it, write the text data, and close the file again.
set theResult to false
set newPath to my modifyPath:thePath adding:"-new"
if ((BOMData's writeToFile:newPath atomically:true) as boolean) then
set fileAccess to current application's NSFileHandle's fileHandleForWritingAtPath:newPath
try
tell fileAccess to seekToEndOfFile()
tell fileAccess to writeData:stringData
set theResult to true
end try
tell fileAccess to closeFile()
end if
return {newPath, theResult as boolean}
end decodeFile:
set theSource to (choose file)
set {newPath, bof} to my decodeFile:(POSIX path of theSource)
By the way, this version of the modifyPath handler uses fewer methods and works properly for paths both with and without extensions:
on modifyPath:thePath adding:addString
set pathString to current application's class "NSString"'s stringWithString:(thePath)
set insertionPoint to pathString's rangeOfString:("(?=(\\.[^./]*+)?/*+$)") options:(current application's NSRegularExpressionSearch)
set newPath to pathString's stringByReplacingCharactersInRange:(insertionPoint) withString:(addString)
-- set newPath to newPath's stringByReplacingOccurrencesOfString:("/*+$") withString:("") options:(current application's NSRegularExpressionSearch) range:({0, newPath's |length|()})
return newPath as text
end modifyPath:adding:
Edit: Regex modified to allow for the possibility of trailing slashes. (Thanks, Yvan.) And the commented-out line will remove any if it’s re-enabled.
It appears - thank you Nigel - that El Capitan doesn’t take care of the case : theExtension is empty string when it’s asked to append it to a path so the original handler must be edited as :
on modifyPath:thePath adding:addString
set pathString to current application's NSString's stringWithString:thePath
set theExtension to pathString's pathExtension()
set thePathNoExt to pathString's stringByDeletingPathExtension()
set newPath to (thePathNoExt's stringByAppendingString:addString)
if theExtension's |length|() > 0 then
set newPath to newPath's stringByAppendingPathExtension:theExtension
end if
return newPath as string
end modifyPath:adding:
For safe I will edit my messages containing the old version.
Yvan KOENIG running Sierra 10.12.3 in French (VALLAURIS, France) dimanche 19 mars 2017 16:39:39