SWIFT: Reading file: NSData successful, String fails. Why? - swift

I'm trying to read large data from file. It is a text file. The following line is successful, data is read into memory:
if let data = NSData(contentsOfFile: path, options: NSDataReadingOptions(), error: &error)
This line return an error:
if let data = String(contentsOfFile:path, encoding: NSUTF8StringEncoding, error: &error)
But why? File is there, only Function is different. And I like to use second one, because I want to split all rows into separate strings in an array:
var array = data.componentsSeparatedByString("\n")
Any hint what to do?
Additional information: There are german umlauts, so code is larger than 127. But the file was saved as UTF-8. How could I load/use non ascii text?

I tried out every option and found the solution I didn't expect:
NSMacOSRomanStringEncoding
This setting accepts also german umlauts!

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…

Use of init(contentsOfFile:encoding:) Swift 4

I want to get a string from a file. I've researched how to do it, and I've found the next code:
import Foundation
// Read data from this file.
let path = "/Users/samallen/file.txt"
do {
// Use contentsOfFile overload.
// ... Specify ASCII encoding.
// ... Ignore errors.
var data = try NSString(contentsOfFile: path,
encoding: String.Encoding.ascii.rawValue)
// If a value was returned, print it.
print(data)
}
The important part are the lines:
var data = try NSString(contentsOfFile: path,
encoding: String.Encoding.ascii.rawValue)
I looked in Apple's documentation about this and found init(contentsOfFile:usedEncoding:)
What I don't get is why you can use String(contentsOfFile:usedEncoding:) instead of init(contentsOfFile:usedEncoding:). Why can you replace String for init? I have seen somthing similar with UIImage.
Thanks in advance

Overwriting the first N bytes in a file in Swift

I'm trying to replace the first N bytes in a file in Swift with my own data, leaving the rest of the file unchanged, e.g. I have the string "OOPS", the file (of any length) currently contains Look, a daisy, and I want it to contain OOPS, a daisy. The built-in functions I've found don't do what I want:
try "OOPS".write(to: path, atomically: false, encoding: String.Encoding.utf8)
replaces the entire file,
let outputStream = OutputStream(url: outputURL, append: false)
outputStream.write("OOPS", maxLength: 4)
behaves the same way, and setting append to true obviously appends my text to the end of the file. Is there an easy way to get the behavior I want?
Use FileHandle.
let handle = FileHandle(forWritingTo: outputURL)
handle.seek(toFileOffset: 0)
handle.write("OOPS".data(using: .utf8))
handle.closeFile()
I leave it to the reader to deal with handling optionals and needing to catch errors.

How can I read a text file with 2 columns in Swift?

I have 2 problems:
I need to open the text file
I need to read in data (organized as 2 columns) and store into either 2 arrays or a multi-dimensional array. The 2 columns are numeric x-y pairs (see below for screenshot of the data), so whatever is easier will work for me, I just need to make sure that the first x-value corresponds to the first y-value.
My attempt:
I tried using this code that I found on this website, but it's giving me errors that I can't figure out:
let path:String = Bundle.mainBundle().pathForResource("README", ofType: "txt")!
textView.text = String(contentsOfFile: path,
encoding: NSUTF8StringEncoding,
error: nil)
Errors for the code for the first problem:
Cannot call value of non-function type 'Bundle'
Use of unresolved identifier 'textView'
For the first problem this works:
let url = Bundle.main.url(forResource: "myResource", withExtension: "txt")
let text = try? String(contentsOf: url!)
print(text ?? "")
for the unresolved identifier part make sure the definition of textView is correct and the source code has your application as its target
for your second problem:
let's say we have these three lines in our text file:
first-one\n
second-two\n
third-three
var pairs = [(Double,Double)]()
for line in (text?.components(separatedBy: "\n").dropFirst())!{
if line != "" {
let sep = # separator is here
let words = line.components(separatedBy: sep)
pairs.append((Double(words[0])!,Double(words[1])!))
}
}
// for reading of the values
for pair in pairs{
print(pair) // equivalent to : (pair.0,pair.1)
}

"contentsOfFile" returning nil, possible cause

The following returns nil when getting the content of a csv file. However, reducing the csv table to 10 rows will work properly, outputting the content of the csv file.
The original csv has about 400,000 characters arranged in 500 rows and 11 columns. What could be causing it to return nil with the original csv?
let dbPath = "/Volumes/Gios2TWD/myDB.csv"
var error: NSError?
let csvContent = NSString(contentsOfFile: dbPath, encoding:NSUTF8StringEncoding, error: &error) as String!
println(csvContent)
println(error)
I'm running XCode Version 6.1 (6A1030)
error:
Optional(Error Domain=NSCocoaErrorDomain Code=261 "The file “myDB.csv” couldn’t be opened using text encoding Unicode (UTF-8)." UserInfo=0x10050c5b0 {NSFilePath=/Volumes/Gios2TWD/myDB.csv, NSStringEncoding=4})
You need code that tests for errors something like this:
let dbPath = "/Volumes/Gios2TWD/myDB.csv"
var error: NSError?
let csvContent = NSString(contentsOfFile: dbPath, encoding:NSUTF8StringEncoding, error: &error)
if csvContent != nil {
// do something with the string
}
else {
println("error: \(error)")
}
Then try to understand any error message. Post the code and full error message to SO if you need help.
With an error message like: "couldn’t be opened using text encoding Unicode (UTF-8)" it is not a UTF-8 file. There may be corruption in the file or it many be another format. Try NSMacOSRomanStringEncoding, it is an 8-bit ASCII encoding that is very forgiving. It also might be another 8-bit ASCII encoding.
Note: Do not explicitly unwrap things unless you are 100% certain that under no circumstances they can never be nil.
Just stumbled upon this question and Zaph's answer with the recommendation to use NSMacOSRomanStringEnconding as the enconding does fix alot of issues indeed - in my case it were umlauts which caused the issue with NSUTF8StringEnconding.
Nevertheless I just wanted to add the latest Swift syntax in case you wanna catch the error and handle it properly
let csvContent: String?
do{
csvContent = try String(contentsOfFile: path!, encoding: NSUTF8StringEncoding)
// file could be read properly - do something with the content ...
} catch {
let nsError = error as NSError
print(nsError.localizedDescription)
}