Max Power
Max Power

Reputation: 992

Error writing to disk in Swift 5 (iOS 12)

I want to store JSON text (as String) in a text file, or rather append each time I have fresh data to add. However, the following code always returns -1 as the return code from output.write(). I'm doing something wrong but I cannot figure out what:

let fileURL = (try! FileManager.default.urls(for: FileManager.SearchPathDirectory.documentDirectory, in: FileManager.SearchPathDomainMask.userDomainMask)).first!.appendingPathComponent("data.json")

let json = "..."
let tenGB = 10 * 1000 * 1000 * 1000
if let output = OutputStream(url: fileURL, append: true) {
    output.open()
    let bytes = output.write(json, maxLength: tenGB)
    if bytes < 0 {
        print("Failure writing to disk")
    } else if bytes == 0 {
        print("Failure writing to disk (capacity)")
    } else {
        print("\(bytes) bytes written to disk")
    }
        output.close()
} else {
    print("Unable to open file")
}

I don't expect the data to be 10 GB at all, more in the kB-MB range, but I thought I'd give it a large value.

The output of streamError: Error Domain=NSPOSIXErrorDomain Code=22 "Invalid argument" UserInfo={_kCFStreamErrorCodeKey=22, _kCFStreamErrorDomainKey=1}

Upvotes: 0

Views: 781

Answers (2)

Michael Salmon
Michael Salmon

Reputation: 1184

I wrapped the code in SwiftUI to test it:

import SwiftUI

let json = "[ 1, 2, 3, 4, 5 ]\n"

func stringWrite(_ string: String) {
    let fileURL = FileManager.default.urls(for: FileManager.SearchPathDirectory.documentDirectory, in: FileManager.SearchPathDomainMask.userDomainMask).first!.appendingPathComponent("data.json")

    if let output = OutputStream(url: fileURL, append: true) {
        output.open()
        let out = [UInt8](string.utf8)
        let bytes = output.write(out, maxLength: out.count)
        if bytes < 0 {
            print("Failure writing to disk")
            print("Error: \(String(describing: output.streamError))")
        } else if bytes == 0 {
            print("Failure writing to disk (capacity)")
        } else {
            print("\(bytes) bytes written to disk")
        }
            output.close()
    } else {
        print("Unable to open file")
    }
}

struct ContentView: View {
    var body: some View {
        Button(
            action: {stringWrite(json)},
            label: { Text("Do it") }
        )
    }
}

The stream expects a pointer to a UInt8 array. I also added printing the error and took the try away from FileManager as it doesn't throw anything. data.json looks like this after running a few times:

[ 1, 2, 3, 4, 5 ]
[ 1, 2, 3, 4, 5 ]
[ 1, 2, 3, 4, 5 ]
[ 1, 2, 3, 4, 5 ]

This query is more or less a duplicate of Writing a String to an NSOutputStream in Swift

Upvotes: 1

m1sh0
m1sh0

Reputation: 2361

As we understand in the comments the problem comes from the 10 GB

What you need is to write data as the size of the data switch the line:

let bytes = output.write(json, maxLength: tenGB)

with

 bytes = output.write(json, maxLength: json.utf8.count)

you need to append data after that, look this question doing something similar question

Upvotes: 2

Related Questions