2

I'm trying to write a Swift program that writes a single character to a file. I've researched this but so far haven't figured out how to do this (note, I'm new to Swift). Note that the text file I'm reading and writing to can contain a series of characters, one per line. I want to read the last character and update the file so it only contains that last character.

Here's what I have so far:

let will_file = "/Users/willf/Drobox/foo.txt"

do {
    let statusStr = try String(contentsOfFile: will_file, encoding: .utf8)
    // find the last character in the string
    var strIndex = statusStr.index(statusStr.endIndex, offsetBy: -1)

    if statusStr[strIndex] == "\n" {
        // I need to access the character just before the last \n
        strIndex = statusStr.index(statusStr.endIndex, offsetBy: -2)
    }

    if statusStr[strIndex] == "y" {
        print("yes")
    } else if statusStr[strIndex] == "n" {
        print("no")
    } else {
        // XXX deal with error here
        print("The char isn't y or n")
    }

    // writing

    // I get a "cannot invoke 'write with an arg list of type (to: String)
    try statusStr[strIndex].write(to: will_file) 
}

I would appreciate advice on how to write the character returned by statusStr[strIndex].

I will further point out that I have read this Read and write a String from text file but I am still confused as to how to write to a text file under my Dropbox folder. I was hoping that there was a write method that could take an absolute path as a string argument but I have not found any doc or code sample showing how to do this that will compile in Xcode 9.2. I have also tried the following code which will not compile:

let dir = FileManager.default.urls(for: .userDirectory, in: .userDomainMask).first
let fileURL = dir?.appendingPathComponent("willf/Dropbox/foo.txt")

// The compiler complains about extra argument 'atomically' in call
try statusStr[strIndex].write(to: fileURL, atomically: false, encoding: .utf8)
Cœur
  • 37,241
  • 25
  • 195
  • 267
Will Fiveash
  • 121
  • 1
  • 6
  • Is the application sandboxed? If yes you cannot access the Dropbox folder in your home folder unless you add appropriate entitlements and open the folder with `NSOpenPanel` – vadian Feb 28 '18 at 09:24
  • Thanks for the info. I don't plan to sandbox this program since I'm doing this for my use only. – Will Fiveash Mar 01 '18 at 16:36
  • Consider that in Xcode 9 apps are sandboxed by default. Please check that the setting is disabled. Rather than using the `String` read/write API I recommend to read and write `Data` which can easily converted from and to `String`. – vadian Mar 01 '18 at 16:42
  • Got it. Note that in my answer below the example code is working for me now. – Will Fiveash Mar 01 '18 at 16:50

1 Answers1

0

I have figured out how to write a character as a string to a file thanks to a couple answers on stack overflow. The key is to coerce a character type to a string type because the string object supports the write method I want to use. Note that I used both the answers in Read and write a String from text file and in Swift Converting Character to String to come up with the solution. Here is the Swift code:

import Cocoa

let will_file = "/Users/willf/Dropbox/foo.txt"

do {
    // Read data from will_file into String object
    let statusStr = try String(contentsOfFile: will_file, encoding: .utf8)
    // find the last character in the string
    var strIndex = statusStr.index(statusStr.endIndex, offsetBy: -1)

    if statusStr[strIndex] == "\n" {
        // I need to access the character just before the last \n
        strIndex = statusStr.index(statusStr.endIndex, offsetBy: -2)
    }

    if statusStr[strIndex] != "n" && statusStr[strIndex] != "y" {
        // XXX deal with error here
        print("The char isn't y or n")
    }

    // Update file so it contains only the last status char
    do {
        // String(statusStr[strIndex]) coerces the statusStr[strIndex] character to a string for writing
        try String(statusStr[strIndex]).write(toFile: will_file, atomically: false, encoding: .utf8)
    } catch {
        print("There was a write error")
    }
} catch {
    print("there is an error!")
}
Will Fiveash
  • 121
  • 1
  • 6