I'm trying to display a .log file in a textview but can't seem to access the filepath properly. When I do it returns nil. I'm using a pod called "SwiftyBeaver" to do the logging. This is what the fileURL looks like:
file:///var/mobile/Containers/Data/Application/5C92E3E6-9E45-4869-9142-AB9E70EE4FCC/Library/Caches/swiftybeaver.log
This is the function I'm using to turn the .log into a string so I can display it in a textView
private func loadTextWithFileName(_ fileName: String) -> String? {
guard let path = Bundle.main.path(forResource: fileName, ofType: "log"),
let contents = try? String(contentsOfFile: path) else {return nil}
return contents
}
This is how I'm displaying the text to the textView
self.loggingTextView.text =
self.loadTextWithFileName(self.file.logFileURL!.absoluteString)
The method that you are using Bundle.main.path() is mainly to search for files in your Bundle.
But it seems your log file is going to be in your Cache directory.
Here is how you can look for a file in your Cache directory of your app
private func loadTextWithFileName(_ fileName: String) -> String? {
if let dir = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first {
let fileURL = dir.appendingPathComponent(fileName)
guard let text = try? String(contentsOf: fileURL, encoding: .utf8) else {
return nil
}
return text
}
return nil
}
You can add a catch block to your try case to check what the error is, in case you don't get the log file details.
Related
I have an issues in changing the file path at every launch of the app.
I have a file("AppConstant.json") in application bundle, and this file I need to copy into application document directory. I am successfully saving "AppConstant.json" file inside the created user folder "MyFolder" on Document directory.
But the problem is when I relaunch the application second time, it's not showing the same path. Also I am using relativepath, but still it not getting.
here is the code
// calling the directory
let stringAppConstant = copyFileFromBundleToDocumentDirectory(resourceFile: "AppConstant", resourceExtension: "json")
// saving or get exit file path
func copyFileFromBundleToDocumentDirectory(resourceFile: String, resourceExtension: String) -> String
{
var stringURLPath = "Error_URLPath"
let fileManager = FileManager.default
let docURL = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
let destFolderPath = URL(string:docURL)?.appendingPathComponent("MyFolder")
let fileName = "\(resourceFile).\(resourceExtension)"
guard let newDestPath = destFolderPath, let sourcePath = Bundle.main.path(forResource: resourceFile, ofType: ".\(resourceExtension)"), let fullDestPath = NSURL(fileURLWithPath: newDestPath.absoluteString).appendingPathComponent(fileName) else {
return stringURLPath
}
if !fileManager.fileExists(atPath: newDestPath.path) {
do {
try fileManager.createDirectory(atPath: newDestPath.path,withIntermediateDirectories: true, attributes: nil)
print("Created folder successfully in :::", newDestPath.path)
} catch {
print("Error in creating folder :::",error.localizedDescription);
}
}
else {
print("Folder is already exist!")
}
if fileManager.fileExists(atPath: fullDestPath.path) {
print("File is exist in ::: \(fullDestPath.path)")
stringURLPath = fullDestPath.path
}
else {
do {
try fileManager.copyItem(atPath: sourcePath, toPath: fullDestPath.path)
print("Saved file successfully in :::", fullDestPath.path)
stringURLPath = fullDestPath.path
} catch {
print("Error in creating file ::: \(error.localizedDescription)")
}
}
return stringURLPath
}
Please help me, where I need to save the path in Sandbox. Is this right way what I implemented.
I am running in device and simulator, both path are different while relaunch
this is the path for first time launch:
/var/mobile/Containers/Data/Application/81B568A7-0932-4C3E-91EB-9DD62416DFE8/Documents/MyFolder/AppConstant.json
relaunch the application I am getting new path:
/var/mobile/Containers/Data/Application/3DAABAC3-0DF5-415B-82A5-72B204311904/Documents/MyFolder/AppConstant.json
NOTE: I create a sample project and I use this same code and it's working. But in existing project it's not working. I am using the same bundle id and profile only for both sample and project. Checked the file added reference, settings, version all are same.
Any idea?
The behavior that the container path changes periodically is normal.
These lines
let destFolderPath = URL(string:docURL)?.appendingPathComponent("MyFolder")
let fileName = "\(resourceFile).\(resourceExtension)"
guard let newDestPath = destFolderPath, let sourcePath = Bundle.main.path(forResource: resourceFile, ofType: ".\(resourceExtension)"), let fullDestPath = NSURL(fileURLWithPath: newDestPath.absoluteString).appendingPathComponent(fileName) else {
return stringURLPath
}
contain a lot of mistakes
URL(string is the wrong API for file paths, it's URL(fileURLWithPath).
The second parameter of path(forResource:ofType:) must not have a leading dot.
The API absoluteString is wrong as parameter of URL(fileURLWithPath
Not a real mistake but don't use NSURL in Swift.
It's highly recommended to use always the URL related API to concatenate paths and get the documents folder from FileManager. Further it's good practice to make the method throw the real error rather than returning a meaningless literal string. And NSSearchPathForDirectoriesInDomains is outdated and should not be used in Swift.
func copyFileFromBundleToDocumentDirectory(resourceFile: String, resourceExtension: String) throws -> URL
{
let sourceURL = Bundle.main.url(forResource: resourceFile, withExtension: resourceExtension)!
let fileManager = FileManager.default
let destFolderURL = try fileManager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false).appendingPathComponent("MyFolder")
let fullDestURL = destFolderURL.appendingPathComponent(resourceFile).appendingPathExtension(resourceExtension)
if !fileManager.fileExists(atPath: destFolderURL.path) {
try fileManager.createDirectory(at: destFolderURL, withIntermediateDirectories: true, attributes: nil)
print("Created folder successfully in :::", destFolderURL.path)
try fileManager.copyItem(at: sourceURL, to: fullDestURL)
print("Saved file successfully in :::", fullDestURL.path)
} else {
print("Folder already exists!")
if fileManager.fileExists(atPath: fullDestURL.path) {
print("File exists in ::: \(fullDestURL.path)")
} else {
try fileManager.copyItem(at: sourceURL, to: fullDestURL)
print("Saved file successfully in :::", fullDestURL.path)
}
}
return fullDestURL
}
Edit 1:
Hi I created the new project and use the same code I posted in main, and it's working. But in the real project it not working.
Not sure what exactly going on in your project, try to debug it. It's part of development as well. :)
If you are in hurry to fix this issue in this weekend try to use the following code snippet.
// collect data from bundle
let constFileURL = Bundle.main.url(forResource: "AppConst", withExtension: "json")!
let data = try! Data(contentsOf: constFileURL)
// try to write data in document directory
do {
let constFileURL = try saveFileInDocumentDirectory(filePath: "MyFolder/AppConst.json", data: data)
// use your `constFileURL`
} catch (let error as FileOperationError) {
switch error {
case .fileAlreadyExists(let url):
let data = try! Data(contentsOf: url)
print(String(data: data, encoding: .utf8))
case .IOError(let error):
print("IO Error \(error)")
}
} catch {
print("Unknown Error \(error)")
}
// Helpers
enum FileOperationError: Error {
case fileAlreadyExists(url: URL)
case IOError(Error)
}
func saveFileInDocumentDirectory(filePath: String, data: Data) throws -> URL {
// final destination path
let destURLPath = fullURLPathOf(filePath, relativeTo: .documentDirectory)
// check for file's existance and throw error if found
guard FileManager.default.fileExists(atPath: destURLPath.path) == false else {
throw FileOperationError.fileAlreadyExists(url: destURLPath)
}
// Create Intermidiate Folders
let intermidiateDicPath = destURLPath.deletingLastPathComponent()
if FileManager.default.fileExists(atPath: intermidiateDicPath.path) == false {
do {
try FileManager.default.createDirectory(at: intermidiateDicPath, withIntermediateDirectories: true, attributes: nil)
} catch {
throw FileOperationError.IOError(error)
}
}
// File Writing
do {
try data.write(to: destURLPath, options: .atomic)
} catch {
throw FileOperationError.IOError(error)
}
return destURLPath
}
func fullURLPathOf(_ relativePath: String, relativeTo dic:FileManager.SearchPathDirectory ) -> URL {
return FileManager.default.urls(for: dic, in: .userDomainMask).first!.appendingPathComponent(relativePath)
}
Original Answer
Why don't you just return "MyFolder/\(fileName)" on successful file operation? If you need to access the path later you can always do that using FileManager APIs.
let docDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let constFilePath = docDir.appendingPathComponent("MyFolder/\(fileName)")
// Access const file data
do {
let fileData = try Data(contentsOf: constFilePath)
// Use you data for any further checking
} catch {
// Error in reading file data
print("Error in file data access : \(error)")
}
I am wondering what the work-around is for downloading files with irregular filenames using Swift's FileManager. For example, downloading a file named "Hello/Goodbye" where the file path looks like:
let filePath = documentDirectory.appendingPathComponent("\(fileName).m4a")
will result in the file downloading to a folder inside documentDirectory named 'Hello' since filePath is "documentDirectory/Hello/Goodbye.m4a". Instead, I want the file to be downloaded under documentDirectory as 'Hello/Goodbye.m4a'. Is there anyway to encode these special characters so that the file path ignores them?
If you need to add a slash "/" to your filename you need to replace it by a colon ":":
let desktopDirectory = FileManager.default.urls(for: .desktopDirectory, in: .userDomainMask).first!
let fileName = "Hello/Goodbye.txt".replacingOccurrences(of: "/", with: ":")
let file = desktopDirectory.appendingPathComponent(fileName)
do {
try "SUCCESS".write(to: file, atomically: true, encoding: .utf8)
} catch {
print(error)
}
extension URL {
func appendingFileName(_ fileName: String, withExtension: String) -> URL {
appendingPathComponent(fileName.replacingOccurrences(of: "/", with: ":")).appendingPathExtension(withExtension)
}
}
let fileName = "Hello/Goodbye"
let pathExtension = "txt"
let file = desktopDirectory.appendingFileName(fileName, withExtension: pathExtension)
do {
try "SUCCESS".write(to: file, atomically: true, encoding: .utf8)
} catch {
print(error)
}
How can I save the console print statements to an exported text file in Xcode ?
I want to save my last console printed statement in a exported log text file in my computer.
You can use a function such as this:
func write(text: String, to fileNamed: String, folder: String = "SavedFiles") {
guard let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first else { return }
guard let writePath = NSURL(fileURLWithPath: path).appendingPathComponent(folder) else { return }
try? FileManager.default.createDirectory(atPath: writePath.path, withIntermediateDirectories: true)
let file = writePath.appendingPathComponent(fileNamed + ".txt")
try? text.write(to: file, atomically: false, encoding: String.Encoding.utf8)
}
and in the command line search for the file that your designated writePath variable is going to give you. You can copy that file elsewhere if you want
I manually created a file amutha.txt in the documents folder. I tried to write data to that file. code which I used is
let string="Amuthapriya"
try string.write(to:fileName, atomically: true, encoding: String.Encoding.utf8)
This is executed correctly means having no exceptions or errors. But then When I open amutha.txt the file is empty. Why the string is not written in that file? What Mistake I am doing?
My code is:
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let documentsDirectory = paths[0]
return documentsDirectory
}
#objc func buttonPressed(sender:UIButton) {
print(sender.titleLabel?.text)
let documentUrl:URL = getDocumentsDirectory()
let fileName=documentUrl.appendingPathComponent("priya.txt", isDirectory: false)
let filePath=fileName.path
print( FileManager.default.fileExists(atPath: filePath))
do {
let string="Amuthapriya"
try string.write(to:fileName, atomically: true, encoding: String.Encoding.utf8)
print("written successfully")
print("filePath: \(filePath)")
} catch {
}
}
Just try to print path of your file in console because you are watching wrong file and check that file if it is available there or not and check content
do {
let string="Amuthapriya"
try string.write(to:fileName, atomically: true, encoding: String.Encoding.utf8)
print("written successfully")
print("filePath: \(filePath)") // check file here
} catch {
}
I manually created a file amutha.txt in the documents folder. But then When I open amutha.txt the file is empty.
But the text is being written to priya.txt.
let fileName=documentUrl.appendingPathComponent("priya.txt", isDirectory: false)
So you are looking in the wrong file.
(Also do not change from file URL to file path string. Use file URL only.)
I'm trying to read and write a file from a path (ex: "/Desktop/folder"). If this can't be done, then from Documents (ex: "/Documents/folder"). I saw and tried several examples, but the problem is that the file is located in a location such:
file:///Users/name/Library/Developer/CoreSimulator/Devices/AE6A47DE-D6D0-49AE-B39F-25C7A2335DC8/data/Containers/Data/Application/09F890C1-081F-46E7-88BC-F8453BAFC1CB/Documents/Test.txt"
0x00006000000af780
Even if i have the "Test.txt" in Documents and even in project.
Here's the code which reads and writes a file at the above location:
let file = "Test.txt" //this is the file. we will write to and read from it
let text = "some text" //just a text
var text2 = ""
if let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
let fileURL = dir.appendingPathComponent(file)
//writing
do {
try text.write(to: fileURL, atomically: false, encoding: .utf8)
}
catch {/* error handling here */print(error)}
//reading
do {
text2 = try String(contentsOf: fileURL, encoding: .utf8)
}
catch {/* error handling here */ print(error)}
}
Is it possible to read and write file from path i need (ex: "Documents/Folder")?
So, like you're doing now, take the documents dir, and append the path you need:
let file = "Test.txt" //this is the file. we will write to and read from it
guard let dir = FileManager.default.urls(for: .documentDirectory,
in: .userDomainMask).first { else return }
let subDir = dir.appendingPathComponent("Folder", isDirectory: true)
let fileURL = subDir.appendingPathComponent(file)
Note that trying to write to that file URL will fail if the sub-folder "Folder" doesn't already exist. You'd have to use one of the file manager createDirectory calls to create the "Folder" directory if it doesn't exist.
I find the solution:
let file = "Test.txt" //this is the file. we will write to and read from it
let text = "some text" //just a text
var text2 = ""
let fileURL = URL(fileURLWithPath: "/Users/name/Documents/Folder/Test.txt")
//writing
do {
try text.write(to: fileURL, atomically: false, encoding: .utf8)
}
catch {/* error handling here */print(error)}
//reading
do {
text2 = try String(contentsOf: fileURL, encoding: .utf8)
var s = ""
}
catch {/* error handling here */ print(error)}
}