b1skit
b1skit

Reputation: 339

How to write to a file at a specific directory in the project?

I'm trying to output some strings I've gathered in my app to a text file.

The text files will always exist in my project, like so:

I'm trying to overwrite whatever is in the file with a new (multi-lined) string:

func writeFile(){
    let theFile: FileHandle? = FileHandle(forWritingAtPath: "./MyFiles/file.txt")
    
    if theFile != nil { // This is always nil!!!
        let data = ("Some text\nline 2\nline3\n" as String).data(using: String.Encoding.utf8)
        
        // Write it to the file
        theFile?.write(data!)
        
        // Close the file
        theFile?.closeFile()
    } else {
        print("Writing failed.")
    }
} // End file writing

However, the FileHandler always returns nil. I suspect that this is because I'm supplying the path and/or filename incorrectly?

I've been googling and stack overflowing for a couple of hours now and I still have no idea of how to fix the problem. How do I specify the correct location and file?

Upvotes: 2

Views: 3965

Answers (3)

Berik
Berik

Reputation: 8143

Generally apps should write only to certain directories. Where an app can write depends on the OS and the security settings. In general, the app's documents directory can be used for generic disk storage.

Since iOS 16 and macOS 13 URL.documentsDirectory is available. Using the Data.write(to:) shortcut for brevity:

let path = URL.documentsDirectory.appending(path: "binary.data")
let data = Data([0xca, 0xfe, 0xba, 0xbe])
try data.write(to: path)

Which will write the binary data to Data/Application/<app-uuid>/Documents/binary.data

Use a FileHandle for more control. The following example shows how to append-only on a file in the documents directory:

let logData = Data(...)
let path = URL.documentsDirectory.appending(path: "persistent.log")

if FileManager().fileExists(atPath: path.path) {
    let fileHandle = try FileHandle(forWritingTo: path)
    fileHandle.seekToEndOfFile()
    try fileHandle.write(contentsOf: logData)
} else {
    // create if not exists
    try logData.write(to: path)
}

To see the file generated by an iOS app:

  • Open Xcode > Window > Devices and Simulators
  • Select the device the app runs on
  • Select the app under Installed Apps
  • Press the gear or ... button
  • Select Download Container...
  • Right click (or double finger tap) the downloaded container and select Show Package Contents

The written file should be in the AppData/Document directory of the container.

Upvotes: 1

Jitendra Singh
Jitendra Singh

Reputation: 2181

You cannot write file outside of the application sandbox. Each iOS app have individual directories Document, Library, tmp to store data.

func writeFile(){
    
    let documentsPath = NSSearchPathForDirectoriesInDomains(.documentsDirectory,.userDomainMask,true)
    let theFile: FileHandle? = FileHandle(forWritingAtPath: "\(documentsPath)/MyFiles/file.txt")
    
    if theFile != nil { // This is always nil!!!
        let data = ("Some text\nline 2\nline3\n" as String).data(using: String.Encoding.utf8)
        
        // Write it to the file
        theFile?.write(data!)
        
        // Close the file
        theFile?.closeFile()
    }
    else {
        print("Writing failed.")
    }
    
} // End file writing

Upvotes: 4

matt
matt

Reputation: 535306

I'm trying to overwrite whatever is in the file

You can't. Writing into the app bundle is forbidden.

The proper approach in this kind of situation is, on first launch, to copy the files into, say, the Documents folder, which is writable. Now you can access them from there, and they are both readable and writable.

Upvotes: 1

Related Questions