How can I read text from a file inside the bundle in Swift? - swift

I downloaded this code from hackingwithswift.com, but it always fails at loading the file where it says "contents could not be loaded". Does anyone have an idea what might cause this problem? Here's my code:
if let filepath = Bundle.main.path(forResource: "german", ofType: "dic") {
do {
contents = try String(contentsOfFile: filepath)
print(contents)
} catch {
print("contents could not be loaded \(error)")
}
} else {
print("file not found")
}
text = contents.components(separatedBy: "\n")
It then outputs the error:
domain=NSCocoaErrorDomain Code=264 "The file “german.dic” couldn’t be opened because the text encoding of its contents can’t be determined." UserInfo={NSFilePath=/private/var/containers/Bundle/Application/0F0F9BBA-3964-41FA-B5EE-114C64F44189/SchoolAid Pro.app/german.dic}

Problem solved: It seems like Swift just doesn't like the .dic format. After copying the contents of the .dic file and pasting them into a .txt file, everything worked out just fine.

Related

reading localizable strings giving output as chinese characters

I am trying to read content of Localizable.strings file in my project as I want to create enum of strings file.
if let filepath = Bundle.main.path(forResource: "Localizable", ofType: "strings", inDirectory: "en.lproj") {
do {
let contents = try String(contentsOfFile: filepath, encoding: .utf16)
print("foundd")
print(contents)
} catch {
print("error==\(error)")
}
}
I get response as
foundd
扰汩獴〰툁ȃђ敮卥渲坅湧汩獨塅湧汩獨㈈ഐᐜā%
If I change encoding to .utf8, I get error as beloow.
error==Error Domain=NSCocoaErrorDomain Code=261 "The file “Localizable.strings” couldn’t be opened using text encoding Unicode (UTF-8)." UserInfo={NSFilePath=/Users/mac/Library/Developer/CoreSimulator/Devices/383D23B1-F6F7-4961-B94B-040F357139D2/data/Containers/Bundle/Application/683BB485-5851-4A12-B391-901B021B9BDA/Excel.app/en.lproj/Localizable.strings, NSStringEncoding=4}
In localization file, I have below
/*
File.strings
Excel
Created by mac on 16/02/2023.
*/
"en"="English";
"en2"="English2";
Any idea why I am getting like this?
Your file is a binary Property List file because there is recognizable bplist file signature:
('扰汩獴〰툁ȃђ敮卥渲坅湧汩獨塅湧汩獨㈈ഐᐜā%'
.encode('utf-16-be')
.decode('latin1'))
'bplist00Ò\x01\x02\x03\x04RenSen2WEnglishXEnglish2\x08\r\x10\x14\x1c\x01\x01\x00%'
You face a mojibake case (above example given in Python for its universal intelligibility).
In any case, converting a binary content to string does not give any sense. You need to know and follow its structure…

Issues updating/appending a string to the end of a file in Swift

I am working on an app where I am trying to write data to a file. Basically the user can set the save directory and then I want to be able to check to see if the file exists. If it doesn't then create it and write the data. If it does exist I want to update/append a string to the end of the file. I have tried following many examples and guides online and it seems everyone is doing this differently. I apologize ahead of time if I am missing something super simple or if this has been asked a hundred times.
I have mostly been working off of this example with no success
Append text or data to text file in Swift
#IBAction func addVariance(_ sender: Any) {
let csvString = "08-06-2019,10:00 AM,10:23 AM,23,Offline,Test"
let directoryURL = URL(string: "/Users/username/Desktop/CSVtest")
let fileURL = directoryURL!.appendingPathComponent("/variances.csv")
let data = NSData(data: csvString.data(using: String.Encoding.utf8, allowLossyConversion: false)!)
if FileManager.default.fileExists(atPath: fileURL.path) {
var err:NSError?
if let fileHandle = try? FileHandle(forUpdating: fileURL) {
fileHandle.seekToEndOfFile()
fileHandle.write(data as Data)
fileHandle.closeFile()
}
else {
print("Can't open fileHandle \(String(describing: err))")
}
}
else {
var err:NSError?
do {
try data.write(to: URL(fileURLWithPath: fileURL.path), options: .atomic)
} catch {
print(error)
}
}
}
When trying to run this function when there is a file in the folder named "variances.csv" I get "Can't open fileHandle nil".
I have tried break points and print() lines. It doesn't seem to be getting past "if let fileHandle = try? FileHandle(forUpdating: fileURL)" and I can't figure out why. fileURL is not nil.
When I try running this function outputting to an empty directory I get.
"Error Domain=NSCocoaErrorDomain Code=513 "You don’t have permission to save the file “variances.csv” in the folder “CSVtest”." UserInfo={NSFilePath=/Users/username/Desktop/CSVtest/variances.csv, NSUnderlyingError=0x600000c9eaf0 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}"

How do I read a file from the filesystem in a Swift command line app?

I'm just starting learning Swift and to teach myself I'm making a simple command line app. It will eventually connect to an online data source but initially I want to load data from a file. I've seen various guides on reading the contents of a file in Swift but none of them seem to work for me. Here is my app so far:
import Foundation
// Set the file path
let path = "/Users⁩/username/workspace⁩/⁨Swift⁩/sis⁩/sis/data.json⁩"
do {
// Get the contents
let contents = try String(contentsOfFile: path, encoding: .utf8)
print(contents)
}
catch let error as NSError {
print("Ooops! Something went wrong: \(error)")
}
Running it outputs:
Ooops! Something went wrong: Error Domain=NSCocoaErrorDomain Code=260 "The file “data.json⁩” couldn’t be opened because there is no such file." UserInfo={NSFilePath=/Users⁩/username/workspace⁩/⁨Swift⁩/sis⁩/sis/data.json⁩, NSUnderlyingError=0x100e19a50 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}
However on the terminal:
$ ls -l /Users/username/workspace/Swift/sis/sis/data.json
-rwxrwxrwx# 1 username staff 165563 16 Jan 17:14 /Users/username/workspace/Swift/sis/sis/data.json
(yeah I relaxed the permissions somewhat just in case that was the problem)
The only slightly anomalous thing I noticed (aside from the inaccurate assertion that the file doesn't exist) was that when I copy and past the path from the XCode output into iTerm2 it puts spaces between each path component:
(pasted as an image as copying it and pasting it back into this form seems to hide the spaces - this is probably irrelevant anyway)
Any help figuring this out would be really appreciated!
I copied your code, downloaded a sample json file to my desktop, and renamed it to example_ 1.json (I included a space inside the file name).
import Foundation
// Set the file path
let path = "/Users⁩/username/Desktop/example_ 1.json⁩"
do {
// Get the contents
let contents = try String(contentsOfFile: path, encoding: .utf8)
print(contents)
}
catch let error as NSError {
print("Ooops! Something went wrong: \(error)")
}
It successfully printed the file. It also worked when I defined contents as a NSString.
let contents = try NSString(contentsOfFile: path,
encoding: String.Encoding.ascii.rawValue)
I am using Swift 4.2.1
you can not read if your command line app is sandboxed. what you can do is to add this file in your project and set path of file by looking the full path of file in identity inspector.
let path = "/Users/snx/EmailReplacer/EmailReplacer/shared_domains_staging.json"
do {
let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe)
let jsonResult = try JSONSerialization.jsonObject(with: data, options: .mutableLeaves)
if let jsonResult = jsonResult as? Dictionary<String, AnyObject> {
print(jsonResult)
}
} catch {
print(error)
}

How do I write to a local file in Swift/XCTest?

My ultimate question is about saving a screenshot from an AppleTV application using XCTest and Swift4 (running on a MacBook paired to the TV device), but I'm having trouble even writing a simple text string to a local file. If I can get this simple file-save working, I'm hoping I can resolve the screenshot issue. (Apologies for making this look like two questions but they appear to be related and resulted from my troubleshooting efforts.)
First, here's what I'm trying to do with a screenshot, based on sample code I found somewhere online:
let appshot = XCUIApplication().windows.firstMatch.screenshot()
let shotpath = FileManager.default.urls(for: .downloadsDirectory, in: .userDomainMask)[0].appendingPathComponent("appshot.png")
let shotpathUrl = URL(string: "file://\(shotpath)")
print("Saving to: \(shotpath)")
do {
try appshot.pngRepresentation.write(to: shotpathUrl!)
} catch {
print("Failed saving screenshot due to \(error)")
}
This gives me the following output:
Saving to: file:///var/mobile/Containers/Data/Application/77D52C66-353B-4029-97D5-48E6BAE35C92/Downloads/appshot.png
Failed saving screenshot due to Error Domain=NSCocoaErrorDomain Code=4 "The file “appshot.png” doesn’t exist." UserInfo={NSFilePath=///var/mobile/Containers/Data/Application/77D52C66-353B-4029-97D5-48E6BAE35C92/Downloads/appshot.png, NSUnderlyingError=0x1c405bc60 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}
Of course, the file doesn't exist because that's the file I'm trying to create. But /var/mobile doesn't exist on my laptop either -- it looks like the path FileManager is building may exist on the AppleTV device, but I want it on my laptop where my test script is executing.
So I backed out to a much more simple case, and even this is giving me problems:
let str = "This is a test"
let path = "file:///Users/haljor/foo.txt"
let pathUrl = URL(string: path)!
print("Path: \(path)")
print("URL: \(pathUrl)")
do {
try str.write(to: pathUrl, atomically: true, encoding: .utf8)
} catch {
print("Caught error writing to \(pathUrl): \(error)")
}
And here's the output:
Path: file:///Users/haljor/foo.txt
URL: file:///Users/haljor/foo.txt
Caught error writing to file:///Users/haljor/foo.txt: Error Domain=NSCocoaErrorDomain Code=4 "The folder “foo.txt” doesn’t exist." UserInfo={NSURL=file:///Users/haljor/foo.txt, NSUserStringVariant=Folder, NSUnderlyingError=0x1c40553f0 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}
Here, it looks like it's trying to write to a folder at the path I specified, not a file. Clearly there's something I'm not understanding in each of these cases.
I don't really have a preference for whether I use a fully-specified path or something using FileManager -- it just needs to land somewhere on my laptop (not the TV device). What am I missing?
You can add an attachment to the test case and save it to disk too. The problem was that Downloads folder may not exist in the container yet. The best way to handle this is via init-once property:
var downloadsFolder: URL = {
let fm = FileManager.default
let folder = fm.urls(for: .downloadsDirectory, in: .userDomainMask)[0]
var isDirectory: ObjCBool = false
if !(fm.fileExists(atPath: folder.path, isDirectory: &isDirectory) && isDirectory.boolValue) {
try! fm.createDirectory(at: folder, withIntermediateDirectories: false, attributes: nil)
}
return folder
}()
func test() {
let appshot = XCUIScreen.main.screenshot()
let attachment = XCTAttachment(screenshot: appshot)
attachment.lifetime = .keepAlways
self.add(attachment)
// Save to container
let url = downloadsFolder.appendingPathComponent("appshot.png")
try! appshot.pngRepresentation.write(to: url)
}
If you want to view the attachment, right-click on the test case, select Jump to Report and expand the tree. You will see the screenshot eventually:

Using Xcode 7/Swift 2 writeToPath to Resources file the call does not fail but no data is written

I am using Xcode 7.3.1 and Swift 2.0. I am using the following code sample:
func writeToResourcesDataDir() {
if let path = NSBundle.mainBundle().pathForResource("TestData", ofType: ".json") {
let str = "Test String"
do {
try str.writeToFile(path, atomically: false, encoding: NSUTF8StringEncoding)
print("writeToFile successful")
} catch {
print("writeToFile failed")
}
} else {
print("Path does not exist")
}
}
Running under Xcode in the see the "writeToFile successful" message.But, also using the simulator, I can display the TestData in the Resources directory and the file does not have the string.I also used a terminal window in Mac to look at the files in the Resources directory and the TestData file is empty (0 bytes).I know I am in the correct Resources directory because there is another file in the directory that has correct data that is used for running the other parts of the program.
I have spent several days now looking at other google entries about data from writeToFile not working and I have tried out every fix or things to try I have found.
Can anyone help?
I added code to accept the boolean return from the call to writeToFile and it returns a false. I'm not sure why a false is returned but the catch isn't invoked.I am not sure how to get the error code that goes with this writeToFile in Swift 2.0.
I am also wondering if this is a write permissions problem.Should I be using the Documents directory instead of the Data directory?
Try something like this. This is swift 2.3 and xcode 8.
let filename = "yourjsonfile"
let documentDirectoryURL = try! NSFileManager.defaultManager().URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: true)
let filePath = documentDirectoryURL.URLByAppendingPathComponent(filename)
let fileExist = filePath?.checkResourceIsReachableAndReturnError(nil)
if (fileExist == true) {
print("Found file")
} else {
print("File not found")
}