How to open file and append a string in it, swift

I am trying to append a string into text file. I am using the following code.

let dirs : [String]? = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.AllDomainsMask, true) as? [String]
if (dirs) != nil {
    let dir = dirs![0] //documents directory
    let path = dir.stringByAppendingPathComponent("votes")
    let text = "some text"

    //writing
    text.writeToFile(path, atomically: true, encoding: NSUTF8StringEncoding, error: nil)

    //reading
    let text2 = String(contentsOfFile: path, encoding: NSUTF8StringEncoding, error: nil)
    println(text2) //prints some text
}

this does not append the string to file. Even if I call this function repeatedly.


Solution 1:

If you want to be able to control whether to append or not, consider using OutputStream. For example:

do {
    let fileURL = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
        .appendingPathComponent("votes.txt")
    
    guard let outputStream = OutputStream(url: fileURL, append: true) else {
        print("Unable to open file")
        return
    }

    outputStream.open()
    let text = "some text\n"
    try outputStream.write(text)
    outputStream.close()
} catch {
    print(error)
}

By the way, this is an extension that lets you easily write a String (or Data) to an OutputStream:

extension OutputStream {
    enum OutputStreamError: Error {
        case stringConversionFailure
        case bufferFailure
        case writeFailure
    }

    /// Write `String` to `OutputStream`
    ///
    /// - parameter string:                The `String` to write.
    /// - parameter encoding:              The `String.Encoding` to use when writing the string. This will default to `.utf8`.
    /// - parameter allowLossyConversion:  Whether to permit lossy conversion when writing the string. Defaults to `false`.

    func write(_ string: String, encoding: String.Encoding = .utf8, allowLossyConversion: Bool = false) throws {
        guard let data = string.data(using: encoding, allowLossyConversion: allowLossyConversion) else {
            throw OutputStreamError.stringConversionFailure
        }
        try write(data)
    }

    /// Write `Data` to `OutputStream`
    ///
    /// - parameter data:                  The `Data` to write.

    func write(_ data: Data) throws {
        try data.withUnsafeBytes { (buffer: UnsafeRawBufferPointer) throws in
            guard var pointer = buffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
                throw OutputStreamError.bufferFailure
            }

            var bytesRemaining = buffer.count

            while bytesRemaining > 0 {
                let bytesWritten = write(pointer, maxLength: bytesRemaining)
                if bytesWritten < 0 {
                    throw OutputStreamError.writeFailure
                }

                bytesRemaining -= bytesWritten
                pointer += bytesWritten
            }
        }
    }
}

For Swift 2 rendition, see previous revision of this answer.

Solution 2:

You can also use FileHandle to append String to your text file. If you just want to append your string the end of your text file just call seekToEndOfFile method, write your string data and just close it when you are done:


FileHandle usage Swift 3 or Later

let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!

// create a new text file at your documents directory or use an existing text file resource url
let fileURL = documentsDirectory.appendingPathComponent("simpleText.txt")
do {
    try Data("Hello World\n".utf8).write(to: fileURL)
} catch {
    print(error) 
}
// open your text file and set the file pointer at the end of it
do {
    let fileHandle = try FileHandle(forWritingTo: fileURL)
    fileHandle.seekToEndOfFile()
    // convert your string to data or load it from another resource
    let str = "Line 1\nLine 2\n"
    let textData = Data(str.utf8)
    // append your text to your text file
    fileHandle.write(textData)
    // close it when done
    fileHandle.closeFile()
    // testing/reading the file edited
    if let text = try? String(contentsOf: fileURL, encoding: .utf8) {
        print(text)  // "Hello World\nLine 1\nLine 2\n\n"
    }
} catch {
    print(error)
}

Solution 3:

Please check the below code as its working for me. Just Add the code as it is:

let theDocumetFolderSavingFiles = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as String
let filePath = "/theUserData.txt"
let thePathToFile = theDocumetFolderSavingFiles.stringByAppendingString(filePath)
let theFileManager = NSFileManager.defaultManager()

if(theFileManager.fileExistsAtPath(thePathToFile)){

        do {

            let stringToStore = "Hello working fine"
            try stringToStore.writeToFile(thePathToFile, atomically: true, encoding: NSUTF8StringEncoding)

        }catch let error as NSError {
            print("we are geting exception\(error.domain)")
        }

        do{
            let fetchResult = try NSString(contentsOfFile: thePathToFile, encoding: NSUTF8StringEncoding)
            print("The Result is:-- \(fetchResult)")
        }catch let errorFound as NSError{
            print("\(errorFound)")
        }

    }else
    {
        // Code to Delete file if existing
        do{
            try theFileManager.removeItemAtPath(thePathToFile)
        }catch let erorFound as NSError{
            print(erorFound)
        }
    }