Unable to save multiple text files in same folder (MacOS Swift Application) - swift

I am trying to save multiple text files in the same folder. So far I can save one text file into a generated folder in my document directory, but I cannot save more than one text file in that same folder.
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let documentsDirectory = paths[0]
let docURL = URL(string: documentsDirectory)!
let dataPath = docURL.appendingPathComponent("User_Notes")
// this is the folder name
if !FileManager.default.fileExists(atPath: dataPath.path) {
do {
try
FileManager.default.createDirectory(atPath: dataPath.path, withIntermediateDirectories: true, attributes: nil)
// try stringToWrite.write(to: &dataPath)
try stringToWrite.write(toFile: "\(dataPath)/\(userNotes)).txt", atomically: true, encoding: String.Encoding.utf8)
} catch {
print(error.localizedDescription)
}
}
if error != nil {
print("Error saving user data.")
}
}

Related

How do I solve the strange "filehandle" problem? [duplicate]

I know there are a few questions pertaining to this, but they're in Objective-C.
How can I access a .txt file included in my app using Swift on an actual iPhone? I want to be able to read and write from it. Here are my project files if you want to take a look. I'm happy to add details if necessary.
Simply by searching in the app bundle for the resource
var filePath = NSBundle.mainBundle().URLForResource("file", withExtension: "txt")
However you can't write to it because it is in the app resources directory and you have to create it in the document directory to write to it
var documentsDirectory: NSURL?
var fileURL: NSURL?
documentsDirectory = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).last!
fileURL = documentsDirectory!.URLByAppendingPathComponent("file.txt")
if (fileURL!.checkResourceIsReachableAndReturnError(nil)) {
print("file exist")
}else{
print("file doesnt exist")
NSData().writeToURL(fileURL!,atomically:true)
}
now you can access it from fileURL
EDIT - 28 August 2018
This is how to do it in Swift 4.2
var filePath = Bundle.main.url(forResource: "file", withExtension: "txt")
To create it in the document directory
if let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last {
let fileURL = documentsDirectory.appendingPathComponent("file.txt")
do {
if try fileURL.checkResourceIsReachable() {
print("file exist")
} else {
print("file doesnt exist")
do {
try Data().write(to: fileURL)
} catch {
print("an error happened while creating the file")
}
}
} catch {
print("an error happened while checking for the file")
}
}
Swift 3, based on Karim’s answer.
Reading
You can read files included in an app’s bundle through the bundle’s resource:
let fileURL = Bundle.main.url(forResource:"filename", withExtension: "txt")
Writing
However, you can’t write there. You will need to create a copy, preferably in the Documents directory:
func makeWritableCopy(named destFileName: String, ofResourceFile originalFileName: String) throws -> URL {
// Get Documents directory in app bundle
guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last else {
fatalError("No document directory found in application bundle.")
}
// Get URL for dest file (in Documents directory)
let writableFileURL = documentsDirectory.appendingPathComponent(destFileName)
// If dest file doesn’t exist yet
if (try? writableFileURL.checkResourceIsReachable()) == nil {
// Get original (unwritable) file’s URL
guard let originalFileURL = Bundle.main.url(forResource: originalFileName, withExtension: nil) else {
fatalError("Cannot find original file “\(originalFileName)” in application bundle’s resources.")
}
// Get original file’s contents
let originalContents = try Data(contentsOf: originalFileURL)
// Write original file’s contents to dest file
try originalContents.write(to: writableFileURL, options: .atomic)
print("Made a writable copy of file “\(originalFileName)” in “\(documentsDirectory)\\\(destFileName)”.")
} else { // Dest file already exists
// Print dest file contents
let contents = try String(contentsOf: writableFileURL, encoding: String.Encoding.utf8)
print("File “\(destFileName)” already exists in “\(documentsDirectory)”.\nContents:\n\(contents)")
}
// Return dest file URL
return writableFileURL
}
Example usage:
let stuffFileURL = try makeWritableCopy(named: "Stuff.txt", ofResourceFile: "Stuff.txt")
try "New contents".write(to: stuffFileURL, atomically: true, encoding: String.Encoding.utf8)
Just a quick update for using this code with Swift 4:
Bundle.main.url(forResource:"YourFile", withExtension: "FileExtension")
And the following has been updated to account for writing the file out:
var myData: Data!
func checkFile() {
if let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last {
let fileURL = documentsDirectory.appendingPathComponent("YourFile.extension")
do {
let fileExists = try fileURL.checkResourceIsReachable()
if fileExists {
print("File exists")
} else {
print("File does not exist, create it")
writeFile(fileURL: fileURL)
}
} catch {
print(error.localizedDescription)
}
}
}
func writeFile(fileURL: URL) {
do {
try myData.write(to: fileURL)
} catch {
print(error.localizedDescription)
}
}
This particular example is not the most flexible, but with a little bit of work you can easily pass in your own file names, extensions and data values.
🎁 Property Wrapper - Fetch and convert to correct data type
This simple wrapper helps you to load any file from any bundle in a cleanest way:
#propertyWrapper struct BundleFile<DataType> {
let name: String
let type: String
let fileManager: FileManager = .default
let bundle: Bundle = .main
let decoder: (Data) -> DataType
var wrappedValue: DataType {
guard let path = bundle.path(forResource: name, ofType: type) else { fatalError("Resource not found: \(name).\(type)") }
guard let data = fileManager.contents(atPath: path) else { fatalError("Can not load file at: \(path)") }
return decoder(data)
}
}
Usage:
#BundleFile(name: "avatar", type: "jpg", decoder: { UIImage(data: $0)! } )
var avatar: UIImage
You can define any decoder to match your needs
Get File From Bundle in Swift 5.1
//For Video File
let stringPath = Bundle.main.path(forResource: "(Your video file name)", ofType: "mov")
let urlVideo = Bundle.main.url(forResource: "Your video file name", withExtension: "mov")
Bundles are read only. You can use NSBundle.mainBundle().pathForResource to access the file as read-only, but for read-write access you need to copy your document to Documents folder or tmp folder.
Bundles can be written. You can use Bundle.main.path to overwrite file by adding it into Copy Bundles Resource.
I have to use a file from another bundle. So, following code worked for me. Needful when you work with a frameworks.
let bundle = Bundle(for: ViewController.self)
let fileName = bundle.path(forResource: "fileName", ofType: "json")

Creating a directory at /Users/Shared/ - using Swift

I am using the following code to create a directory in /Users/Shared/ to share data of my application between all users. When i run the code gotthe below output.
2019-03-08 19:41:41.751418+0530 MyApp[7224:488397] Couldn't create document directory
2019-03-08 19:41:41.754026+0530 MyApp[7224:488397] Document directory is file:///Users/Appname
let fileManager = FileManager.default
if let tDocumentDirectory = fileManager.urls(for: .userDirectory, in: .localDomainMask).first {
let filePath = tDocumentDirectory.appendingPathComponent("Appname")
if !fileManager.fileExists(atPath: filePath.path) {
do {
try fileManager.createDirectory(atPath: filePath.path, withIntermediateDirectories: true, attributes: nil)
} catch {
NSLog("Couldn't create document directory")
}
}
NSLog("Document directory is \(filePath)")
}
I don't why this error occured. How this can be done?
Please read the log messages carefully.
You are trying to create the folder file:///Users/Appname which is not in /Users/Shared. You have to append "Shared/Appname".
And you are encouraged to use the URL related API of FileManager (and less confusing variable names 😉)
let fileManager = FileManager.default
let userDirectory = try! fileManager.url (for: .userDirectory, in: .localDomainMask, appropriateFor: nil, create: false)
let folderURL = userDirectory.appendingPathComponent("Shared/Appname")
if !fileManager.fileExists(atPath: folderURL.path) {
do {
try fileManager.createDirectory(at: folderURL, withIntermediateDirectories: true, attributes: nil)
} catch {
print("Couldn't create document directory", error)
}
}
print("Document directory is \(folderURL)")

How To Get This To Save To Where My App Is Located

Save data to file
let fileName = "Test"
let DocumentDirURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let fileURL = DocumentDirURL.appendingPathComponent(fileName).appendingPathExtension("txt")
print("FilePath: \(fileURL.path)")
let writeString = "Write this text to the fileURL as text in iOS using Swift"
do {
// Write to the file
try writeString.write(to: fileURL, atomically: true, encoding: String.Encoding.utf8)
} catch let error as NSError {
print("Failed writing to URL: \(fileURL), Error: " + error.localizedDescription)
}
var readString = "" // Used to store the file contents
do {
// Read the file contents
readString = try String(contentsOf: fileURL)
} catch let error as NSError {
print("Failed reading from URL: \(fileURL), Error: " + error.localizedDescription)
}
print("File Text: \(readString)")
How can I get this to save the Test.txt file to save where my App directory is. I don't know where this is saving the Text File to.

Can't save a file in a Documents directory in macOS

I created a function to save a data.txt file in ~/Documents directory.
But it doesn't save a file at all.
func SaveFile(){
print("save file")
let file_name = "data.txt"
let text = "12345"
let fm = FileManager.default
do {
let docsurl = try! fm.url(for: .documentDirectory, in: .userDomainMask, appropriateFor:nil, create:false)
let fileURL = docsurl.appendingPathComponent(file_name)
try text.write( to: fileURL, atomically: false, encoding: String.Encoding.utf8 )
} catch {
print("error: \(error)")
}
}
In the output area there is only text save file.
What am I doing wrong?

How do I create a custom file in swift?

For my mac application (in swift), I currently save data by writing & reading .txt files. To make the files look more professional, how can I write a file with:
a custom extension
a custom preview image
data structured like a plist (maybe xml?)
EDIT: This is what I am currently using (not that it is useful):
let root = XMLElement(name: "root")
let xml = XMLDocument(rootElement: root)
root.addChild(XMLElement(name: "value", stringValue: "125"))
root.addChild(XMLElement(name: "key", stringValue: "kF15304g3DlJkR"))
let fileName = "File"
let directory = try? FileManager.default.url(for: .desktopDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
if var fileURL = directory?.appendingPathComponent(fileName).appendingPathExtension("xml") {
do {
try xml.xmlString.write(to: fileURL, atomically: true, encoding: .utf8)
} catch {
print(error.localizedDescription)
}
do {
var resourceValues = URLResourceValues()
resourceValues.hasHiddenExtension = true
//resourceValues.thumbnail is get-only!?!? :( how do I set it?
try fileURL.setResourceValues(resourceValues)
} catch {
print(error.localizedDescription)
}
}