FYI, I append JSON files millions of times per file. Here's the code:
func saveBAToJSON(BA: myCustomClass) {
let fileName = "created from BA"
let ArchiveURL = getArchiveURL(fileName: fileName, ext: "JSON")
var ArchiveDirectoryPath = fileDirPath
let localFileManager = FileManager()
do {
let resources = try? ArchiveURL.resourceValues(forKeys: [.fileSizeKey])
let fileSize = resources?.fileSize ?? 0
/* The JSON file is appended many times and it must be limited in size otherwise memory is over taxed. maxFileSize is a global var that is machine specific. */
if fileSize > maxFileSize {
let dirContents = try! localFileManager.contentsOfDirectory(atPath: ArchiveDirectoryPath)
var elemFiles = 0
/* If a file would exceed MaxFileSize, start a new file copying it and appending an incremented counter to the name. */
for elem in 0..<dirContents.count { if dirContents[elem].contains(fileName) { elemFiles += 1 } }
try FileManager.default.copyItem(at: ArchiveURL, to: getArchiveURL(fileName: fileName+"-\(elemFiles)", ext: "JSON"))
try FileManager.default.removeItem(at: ArchiveURL)
}
} catch { print("\(Date.now):\(#file):\(#line) saveBAToJSON():fileSize", error) }
do {
let myJSONencoder = JSONEncoder()
myJSONencoder.nonConformingFloatEncodingStrategy = .convertToString(positiveInfinity: "+Infinity", negativeInfinity: "-Infinity", nan: "NaN")
var data = try myJSONencoder.encode(BA)
if let fileHandle = try? FileHandle(forWritingTo: ArchiveURL) {
defer {
fileHandle.closeFile()
}
/* This is the main trick: truncate the repeating JSON components from the top of file to be appended, strip the JSON components at the end of the file to append-to (after converting to base64) replacing it with a comma (in my case). Write to file. */
let truncateCount = UInt64(36 + filename.count + String(BA.myCustomClassElement1).count)
/* you must count chars in your specific JSON's to get this right. I'm sure this could be coded to adapt to any JSON file. */
let strippedRange = data.range(of: Data(base64Encoded: "my base64 encoded repeating components at end-of-file" )!)
let commaData = Data(base64Encoded: "LA==")!
data.replaceSubrange(strippedRange!, with: commaData )
let end = try fileHandle.seekToEnd()
if end > truncateCount {
try fileHandle.truncate(atOffset: end - truncateCount )
try fileHandle.write(contentsOf: data )
}
}
else { try data.write(to: ArchiveURL, options: [.atomic, .noFileProtection]) }
} catch { print("\(Date.now):\(#file):\(#line) saveBAToJSON():fileSize", error) }
}
Share and Enjoy
homage Eskimo