0

Below is my code - I have tried to get the document directory path and with standard FileManager singleton tried to create a file, but I am not able to create the file, as the error -

Unable to store data: Error Domain=NSCocoaErrorDomain Code=4 "The file “CrashLog.txt” doesn’t exist."

UserInfo={NSFilePath=file:///Users/ABC/Library/Developer/CoreSimulator/Devices/87317777-63E7-422B-A55F-878E3267AFB8/data/Containers/Data/Application/4B41AA87-E4B9-4EE4-A67F-AC3B018913CC/Documents/CrashLog, NSUnderlyingError=0x600000244ec0 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}

Code in development -

let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
if (paths.count > 0) {
    let documentsDirectory = paths[0]
    let logFilePath = URL(fileURLWithPath: documentsDirectory).appendingPathComponent("CrashLog.txt").absoluteString
    let _string = "Hello"
    //Create file at given path
    let data = _string.data(using: .utf8)
    //let attributes = FileManager.default.attributesOfItem(atPath: logFilePath)
    let fileExists : Bool = FileManager.default.fileExists(atPath: logFilePath)
    print(fileExists)
    let isFileCreated =  FileManager.default.createFile(atPath: logFilePath, contents: data, attributes: nil)
    print("ifFileCreated", isFileCreated)
}
Ozgur Vatansever
  • 49,246
  • 17
  • 84
  • 119
Sunil
  • 55
  • 1
  • 7
  • Nvm, I didn't properly read your code. Whatever @Larme says! – Akaino Sep 24 '18 at 14:18
  • `let logFilePath = URL(fileURLWithPath: documentsDirectory).appendingPathComponent("CrashLog.txt")` instead, don't use the `absoluteString`, and so: `(atPath: logFilePath.path)` (twice) should do the trick. – Larme Sep 24 '18 at 14:20
  • Related: [NSFileManager.defaultManager().fileExistsAtPath returns false instead of true](https://stackoverflow.com/questions/34135305/nsfilemanager-defaultmanager-fileexistsatpath-returns-false-instead-of-true) – Martin R Sep 24 '18 at 14:21
  • I don't remember the exact answer for this, but bear in mind that `.absoluteString` and `.path` return different things, I remember having an issue that was caused by using absoluteString instead of path. – Scriptable Sep 24 '18 at 14:22

3 Answers3

2

Here's my take on what you've done. Adopt the URL-based means of working with files. The best way to write data (for this example, at least), is to use Data's ability (not FileManager) to write to a file, again, using a URL. In most cases, you don't need to worry whether the file exists or not; just do it, and handle any error that arises.

    if var url = try? FileManager.default.url(for: .documentDirectory,
                                              in: .userDomainMask,
                                              appropriateFor: nil,
                                              create: false) {
        url = url.appendingPathComponent("CrashLog").appendingPathExtension("txt")
        let _string = "Hello"
        if let data = _string.data(using: .utf8) {
            do {
                try data.write(to: url)
                print("successful")
            } catch {
                print("unsuccessful")
            }
        }
    }
Extra Savoir-Faire
  • 6,026
  • 4
  • 29
  • 47
1

The API absoluteString is wrong. The correct API is path

absoluteString returns the entire URL string representation including the scheme file://. On the other hand the path API of FileManager expects file system paths, the string without the scheme.

You are encouraged to use the URL related API anyway and you can write Data directly to disk without explicitly creating a file.

let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let logFileURL = documentsURL.appendingPathComponent("CrashLog.txt")
let string = "Hello"

let data = Data(string.utf8)

let fileExists = FileManager.default.fileExists(atPath: logFileURL.path)
print(fileExists)
do {
    try data.write(to: logFileURL)
    print("data written")
} catch { print(error) }
vadian
  • 274,689
  • 30
  • 353
  • 361
  • I used `absoluteString` everywhere and file creation always failed. Wasted a lot of time trying to figure out where the problem was in these simple five lines of code.... When I started using [path()](https://developer.apple.com/documentation/foundation/url/3988473-path) (as of iOS 16.0), everything worked. Thanks a ton! – NightFuryLxD Mar 07 '23 at 11:20
0

The appendingPathComponent method if the receiver (e.g. parameter) does not end with a trailing slash, then it may read file metadata to determine whether the resulting path is a directory. That means it may produce the error you are seeing, so better use the appendingPathComponent(_:isDirectory:) instead.

For example:

let logFilePath = URL(fileURLWithPath: documentsDirectory).appendingPathComponent("CrashLog.txt", isDirectory: false).absoluteString
Christos Koninis
  • 1,499
  • 1
  • 15
  • 28