How to use createFile using Swift 4

do {
        let fm = FileManager.default
        fm.createFile(atPath: String, contents: Data?, attributes: [FileAttributeKey : Any]?)
    }
catch let error as NSError {
        print("error")
    }


How do I setup the Data and the FileAttributeKey?


I want to access a file.

Parse the contents of the file.

Write the changed data to another file name to disk.

I am using MacOS 10.13.x, not iOS.


Thanks

Post not yet marked as solved Up vote post of BugMage Down vote post of BugMage
15k views

Replies

In general, you should not use "createFile" at all. First, you can tell it's outdated API by the fact that it doesn't throw on errors. Second, it's preferable to use URLs to represent file locations, rather than paths.


If you have a Data value, containing the data you want to write to your file, use the "write(to:options:)" method on that Data value to write it to a URL.


If you must use "createFile", you can just omit the "attributes:" parameter, or specify it as nil. The documentation doesn't say, but I guess specifying "nil" for the "contents:" parameter creates an empty file, otherwise you pass a Data value to write the contents into the new file. Note that, because "createFile" doesn't throw errors, you don't need a do/catch block around it, but you should check the true/false return value.


But don't use "createFile" unless you have to.

Thanks QuincyMorris


I am still learning Swift 4 yet the appropriate frameworks to use file management is not clear. I tried a google search for training but no luck. I cannot believe the lack of resources. With that said...


I want to access a file.

Parse the contents of the file. (In Memory ???)

Write the changed data (string) to another or new file name to disk.

I am using MacOS 10.13.x, not iOS.


You had mentioned using "write(to:options:)" method. I assume that this is OSX Foundation method for Swift 4. Is there a bare minimum example code for File management using "write(to:options:)" method.


Added Info: I do not want to use any UI.


Thanks

"Data" (with an uppercase D) is a Foundation type:


https://developer.apple.com/documentation/foundation/data


That's where you'll find the "write(to:options:)" method, and also a method for reading data from a file into a Data instance.


In terms of the other things you want to , you're going to have to build up a skill set. There's no easy way to jump straight to a solution.

I was only wanting to start a discussion about Swift & FileManager.

import Cocoa

func writeToFile(fileName: String, writeText: String) -> Bool {
    let desktopURL = try! FileManager.default.url(for: .desktopDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
    print("desktopURL: " + String(describing: desktopURL))
    let fileURL = desktopURL.appendingPathComponent(fileName).appendingPathExtension("txt")

    print("File Path: \(fileURL.path)")

    do {
        try writeText.write(to: fileURL, atomically: true, encoding: String.Encoding.utf8)
    } catch let error as NSError {
        print("Error: fileURL failed to write: \n\(error)" )
        return false
    }
    return true
}

func fileExist(path: String) -> Bool {
    var isDirectory: ObjCBool = false
    let fm = FileManager.default
    return (fm.fileExists(atPath: path, isDirectory: &isDirectory))
}

func readFromFile(fileName: String, readText: inout String) -> Bool {

    let desktopURL = try! FileManager.default.url(for: .desktopDirectory, in: .userDomainMask, appropriateFor: nil, create: true)


    print("desktopURL: " + String(describing: desktopURL))

    let fileURL = desktopURL.appendingPathComponent(fileName).appendingPathExtension("txt")

    if !(fileExist(path: fileURL.path)) {
        print("File Does Not Exist...")
        return false
    }

    print("File Path: \(fileURL.path)")

    do {
        readText = try String(contentsOf: fileURL)
    } catch let error as NSError {
        print("Error: fileURL failed to read: \n\(error)" )
        return false
    }
    return true
}

var fName = "HelloFile"

var fileReadString = ""
print ("2: " + String(readFromFile(fileName: fName, readText: &fileReadString)) + "\n" + fileReadString)

var fileWriteString = "We are having fun eating Apples!"
print ("1: " + String(writeToFile(fileName: fName, writeText: fileWriteString))  + "\n" + fileWriteString)

fileReadString = ""
print ("2: " + String(readFromFile(fileName: fName, readText: &fileReadString)) + "\n" + fileReadString)


Results:

desktopURL: file:///Users/BugMage/Desktop/

File Does Not Exist...

2: false


desktopURL: file:///Users/BugMage/Desktop/

File Path: /Users/BugMage/Desktop/HelloFile.txt

1: true

We are having fun eating Apples!


desktopURL: file:///Users/BugMage/Desktop/

File Path: /Users/BugMage/Desktop/HelloFile.txt

2: true

We are having fun eating Apples!


Program ended with exit code: 0


This code mainly deals with strings that writes to and reads from a file but how does it handle LARGE FILES?


BugMage

One comment about your code:


It is generally regarded as incorrect to check whether a file exists before reading from it. That's because of a potential race condition, where the existence of the file can change after you check, but before the read happens. The better approach is to try reading the file, and examine the error, if there is one. Or, if you are creating a new file, you would just try writing to it, and examine any error to find out if the file already existed.


>> how does it handle LARGE FILES?


It's kind of up to you. If you use the String class to do reading and writing, it's likely that the entire file is going to be read and converted to a String in memory. (The String is in memory, the file's raw data isn't necessarily all in memory, since files can be read with memory mapping.) This is probably fine for strings up to several megabytes.


For very large files, you probably need to read the raw data yourself, and create the string in pieces (which, depending on your app, might not need to all be in memory at once). This is not trivial, though, because of the complexities of decoding UTF-8 — you must divide the file at points which don't break into any multi-byte sequences. Because of the way UTF-8 is designed, you can (for example) scan forward or backward in file data until you find a CR or LF character, and break there.


But such optimizations are very sensitive to your app's constraints. Sometimes doing the simple, obvious thing is best, sometimes you have to work hard. There is no single answer.