Einlesen einer Datei

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Einlesen einer Datei

    Hallo liebe Leut'

    ich habe vor ein paar Tagen angefangen, mich mit Swift zu beschäftigen.
    Ich bin auch erst seit drei Wochen auf OS X unterwegs. Viele Wege, Eigenarten und Verhaltensweisen vom System sind mir demnach auch noch fremd. Auch wenn mir Unixoide nicht fremd sind. Selbst GNU/Hurd mit seinem Mach-Kernel (welcher ja auch bei Darwin zum einsatz kommt) hatte ich vor ca. 10 oder 12 Jahren schon auf dem PC laufen.

    Installiert habe ich 10.11.1 und ich nutze XCode 7.1, demnach also Swift 2.
    Nun versuche ich mich gerade etwas in die Sprache einzufuchsen und backe erstmal kleine Brötchen.
    Als ich eine Möglichkeit suchte, eine simple Text-Datei einzulesen, graute es mir ein wenig. Entweder hab ich einen völlig falschen Such-Term genutzt (read file swift), oder es ist wirklich so kompliziert, eine Datei in den Speicher zu lesen.
    Ich bin da andere Wege gewohnt

    Perl-Quellcode

    1. open(my $FH, '<', "data.txt")
    oder

    Quellcode: Visual Basic.Net

    1. Using reader As StreamReder = New StreamReader("data.txt")
    2. line = reader.ReadLine
    3. End Using

    Aber der Weg in Swift hat's echt in sich :)
    Folgendes habe ich auf StackOverflow gefunden:

    Quellcode

    1. class StreamReader {
    2. let encoding : UInt
    3. let chunkSize : Int
    4. var fileHandle : NSFileHandle!
    5. let buffer : NSMutableData!
    6. let delimData : NSData!
    7. var atEof : Bool = false
    8. init?(path: String, delimiter: String = "\n", encoding : UInt = NSUTF8StringEncoding, chunkSize : Int = 4096) {
    9. self.chunkSize = chunkSize
    10. self.encoding = encoding
    11. if let fileHandle = NSFileHandle(forReadingAtPath: path),
    12. delimData = delimiter.dataUsingEncoding(encoding),
    13. buffer = NSMutableData(capacity: chunkSize)
    14. {
    15. self.fileHandle = fileHandle
    16. self.delimData = delimData
    17. self.buffer = buffer
    18. } else {
    19. self.fileHandle = nil
    20. self.delimData = nil
    21. self.buffer = nil
    22. return nil
    23. }
    24. }
    25. deinit {
    26. self.close()
    27. }
    28. /// Return next line, or nil on EOF.
    29. func nextLine() -> String? {
    30. precondition(fileHandle != nil, "Attempt to read from closed file")
    31. if atEof {
    32. return nil
    33. }
    34. // Read data chunks from file until a line delimiter is found:
    35. var range = buffer.rangeOfData(delimData, options: [], range: NSMakeRange(0, buffer.length))
    36. while range.location == NSNotFound {
    37. let tmpData = fileHandle.readDataOfLength(chunkSize)
    38. if tmpData.length == 0 {
    39. // EOF or read error.
    40. atEof = true
    41. if buffer.length > 0 {
    42. // Buffer contains last line in file (not terminated by delimiter).
    43. let line = NSString(data: buffer, encoding: encoding)
    44. buffer.length = 0
    45. return line as String?
    46. }
    47. // No more lines.
    48. return nil
    49. }
    50. buffer.appendData(tmpData)
    51. range = buffer.rangeOfData(delimData, options: [], range: NSMakeRange(0, buffer.length))
    52. }
    53. // Convert complete line (excluding the delimiter) to a string:
    54. let line = NSString(data: buffer.subdataWithRange(NSMakeRange(0, range.location)),
    55. encoding: encoding)
    56. // Remove line (and the delimiter) from the buffer:
    57. buffer.replaceBytesInRange(NSMakeRange(0, range.location + range.length), withBytes: nil, length: 0)
    58. return line as String?
    59. }
    60. /// Start reading from the beginning of file.
    61. func rewind() -> Void {
    62. fileHandle.seekToFileOffset(0)
    63. buffer.length = 0
    64. atEof = false
    65. }
    66. /// Close the underlying file. No reading must be done after calling this method.
    67. func close() -> Void {
    68. fileHandle?.closeFile()
    69. fileHandle = nil
    70. }
    71. }
    Alles anzeigen
    Sicher ... in Perl oder VB.net wird im Hintergrund genau so viel passieren, aber dies blieb mir bisher verborgen und ich musste mich auch nicht darum kümmern, weil es funktionierte.

    Wenn ich mittels dieser Klasse versuche, eine Datei zu lesen, bekomme ich nichts zurück ...

    Quellcode

    1. if let aSR = StreamReader(path: "/Users/hwd/Desktop/text.txt") {
    2. defer {
    3. aSR.close()
    4. }
    5. while let line = aSR.nextLine() {
    6. print(line)
    7. }
    8. }

    Im Einfachsten (und Wahrscheinlichsten) Fall bin ich einfach zu blöd für und ich habe das einfach nicht verstanden.
    Da ich die Methode aber 1:1 vom Ersteller der Antwort auf SO übernommen habe, wundert es mich schon, dass ich da keine Ausgabe bekomme.
    Die zu lesende Datei existiert und ist mit drei Zeilen gefüllt:

    Quellcode

    1. hwd@hwds-iMac:~/Desktop$ cat text.txt
    2. Zeile 1
    3. Line 2
    4. Ha!
    5. hwd@hwds-iMac:~/Desktop$

    Danke schonmal :)
  • Playground execution failed: /var/folders/fx/v6t6rfp535q6s5sxw8f3mnzh0000gn/T/./lldb/14535/playground1800.swift:8:24: error: 'stringWithContentsOfFile' is unavailable: APIs deprecated as of OS X 10.9 and earlier are unavailable in Swift

    :S

    Wie öffnet ihr denn eure Dateien?
    Solch grundlegende Funktion kann doch nicht so schwierig zu nutzen sein ...
  • hirnwunde schrieb:

    Playground execution failed: /var/folders/fx/v6t6rfp535q6s5sxw8f3mnzh0000gn/T/./lldb/14535/playground1800.swift:8:24: error: 'stringWithContentsOfFile' is unavailable: APIs deprecated as of OS X 10.9 and earlier are unavailable in Swift

    :S

    Wie öffnet ihr denn eure Dateien?
    Solch grundlegende Funktion kann doch nicht so schwierig zu nutzen sein ...
    du musst die mit den weiteren parametern verwenden. die anderen sind deprecated.
    steht ja auch in der doku etc...
  • hirnwunde schrieb:

    Wie öffnet ihr denn eure Dateien?
    Normalerweise nicht mit Swift.

    hirnwunde schrieb:

    Solch grundlegende Funktion kann doch nicht so schwierig zu nutzen sein ...

    Mal so probiert?

    JavaScript-Quellcode

    1. let thePath = "Macintosh HD/Users/hirnwunde/Desktop/data.txt"
    2. let theText = try NSString(contentsOfFile: thePath, encoding: NSUTF8StringEncoding)

    Ergänzung:
    Du wirst sicher auch was schreiben wollen.

    JavaScript-Quellcode

    1. let thePath = "Macintosh HD/Users/hirnwunde/Desktop/data.txt"
    2. let myWorld = "Hello World."
    3. try text.writeToFile(thePath, atomically: false, encoding: NSUTF8StringEncoding)
    * Kann Spuren von Erdnüssen enthalten.

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von NSObject ()

  • NSObject schrieb:

    Mal so probiert?
    Jo.
    Nüscht.
    Ein späteres print("Ausgabe:\n\(theText)) wird erst garnicht nicht erreicht. Es wird zumindest nichts im Playground ausgegeben. Nicht mal "Ausgabe:"

    Ich habe mal versucht, dies mit einer Überprüfung auf die Existenz zu versehen

    Quellcode

    1. let thePath = "/Users/hwd/Desktop/data.txt"
    2. if (NSFileManager.defaultManager().fileExistsAtPath(thePath)) {
    3. print("OK")
    4. } else {
    5. print("NOPE")
    6. }
    Ich bekomme weder ein "OK" noch ein "NOPE" :huh: ?(

    Auch wenn ich nicht wirklich daran glaube ... kann es damit zusammenhängen, das ich OSX auf einem PC nutze (Stichwort Hackintosh) und nicht auf Apple-Hardware?
  • hirnwunde schrieb:


    Quellcode

    1. let thePath = "/Users/hwd/Desktop/data.txt"
    2. if (NSFileManager.defaultManager().fileExistsAtPath(thePath)) {
    3. print("OK")
    4. } else {
    5. print("NOPE")
    6. }
    Ich bekomme weder ein "OK" noch ein "NOPE" :huh: ?(

    Auch wenn ich nicht wirklich daran glaube ... kann es damit zusammenhängen, das ich OSX auf einem PC nutze (Stichwort Hackintosh) und nicht auf Apple-Hardware?
    Wenn nich das bei mir auf dem Mac eingebe funktioniert es und das file auf dem Desktop wird erkannt.
  • Wakko schrieb:

    hirnwunde schrieb:

    Quellcode

    1. let thePath = "/Users/hwd/Desktop/data.txt"
    2. if (NSFileManager.defaultManager().fileExistsAtPath(thePath)) {
    3. print("OK")
    4. } else {
    5. print("NOPE")
    6. }
    Ich bekomme weder ein "OK" noch ein "NOPE" :huh: ?(

    Auch wenn ich nicht wirklich daran glaube ... kann es damit zusammenhängen, das ich OSX auf einem PC nutze (Stichwort Hackintosh) und nicht auf Apple-Hardware?
    Wenn nich das bei mir auf dem Mac eingebe funktioniert es und das file auf dem Desktop wird erkannt.
    Ist bei mir in einem Playground auch so, aber wenn man dann mal in Zeile zwei

    let theText = try NSString(contentsOfFile: thePath, encoding: NSUTF8StringEncoding)

    einfügt, passiert nix mehr. Das liegt aber offensichtlich mal wieder am Playground, denn wenn man den selben Code in ein Projekt gießt, dann funktioniert das auch mit dem Einlesen der Datei. In Playgrounds funktioniert nicht immer alles, was im „wirklichen Leben“ funktioniert.
  • Michael schrieb:

    Das liegt aber offensichtlich mal wieder am Playground, denn wenn man den selben Code in ein Projekt gießt, dann funktioniert das auch mit dem Einlesen der Datei. In Playgrounds funktioniert nicht immer alles, was im „wirklichen Leben“ funktioniert.
    Das gleiche Verhalten habe ich auch. Ich verwende zum Testen anstelle der Playgrounds lieber swift(1). Das ist wesentlich stabiler und macht das, was es soll.

    @hirnwunde: Das Einlesen kann übrigens auch in die Hose gehen, wenn die Textdatei einen 8-Bit-Zeichensatz (z. B. MacRoman oder Latin-1) und Umlaute oder andere Zeichen mit einem Code > 127 verwendet.

    BTW: Wenn du ernsthaft für Mac oder iOS entwickeln möchtest, kauf dir einen Mac.
    „Meine Komplikation hatte eine Komplikation.“
  • 's klappt nun.

    In einem Projekt und nicht im Playground.
    Und eine etwas andere Variante:

    Quellcode

    1. let thePath = "/Users/hwd/Desktop/text.txt"
    2. if (NSFileManager.defaultManager().fileExistsAtPath(thePath)) {
    3. print("OK")
    4. let theText: NSString!
    5. do {
    6. theText = try NSString(contentsOfFile: thePath, encoding: NSUTF8StringEncoding)
    7. }catch _ {
    8. theText = nil
    9. }
    10. print("Ausgabe:\n\(theText)")
    11. print("Ende")
    12. } else {
    13. print("NOPE")
    14. }
    Alles anzeigen

    [Blockierte Grafik: http://www.hirnwun.de/pic/out_20151106.png]

    macmoonshine schrieb:

    Das Einlesen kann übrigens auch in die Hose gehen, wenn die Textdatei einen 8-Bit-Zeichensatz (z. B. MacRoman oder Latin-1) und Umlaute oder andere Zeichen mit einem Code > 127 verwendet.
    Ja, wenn ich das Encoding hardcode, ist dies sicher der Fall.
    Danke für den Hinweis.
    Um sicher zu gehen müsste man also erstmal das Encoding der Datei herausfinden. Mein erster Einfall wäre file -I foo.bar (grosses i, kein kleines L ;) )
    Aber da gibt es sicher auch Swift-Interne Lösungen, die ich bei Bedarf nutzen kann.

    Vorerst ging es mir eher um die generelle Lösung, eine Datei zu öffnen und deren Inhalt dem Programm verfügbar zu machen.
    Und dies wollte ja im Playground nicht klappen.


    Thallius schrieb:

    aber vielleicht ist ja einfach das Sandboxing defaultmässig an
    Das scheint der Fall zu sein.
    Relative Pfadangaben, die ich in meinen ersten Versuchen hatte, lagen alle unter /var.