Чтение и запись строки из текстового файла

223

Мне нужно читать и записывать данные в/из текстового файла, но мне не удалось выяснить, как это сделать.

Я нашел этот пример кода в Swift iBook, но я до сих пор не знаю, как писать или читать данные.

import Cocoa

class DataImporter
{
    /*
    DataImporter is a class to import data from an external file.
    The class is assumed to take a non-trivial amount of time to initialize.
    */
    var fileName = "data.txt"
    // the DataImporter class would provide data importing functionality here
}

class DataManager
{
    @lazy var importer = DataImporter()
    var data = String[]()
    // the DataManager class would provide data management functionality here
}

let manager = DataManager()
manager.data += "Some data"
manager.data += "Some more data"
// the DataImporter instance for the importer property has not yet been created"

println(manager.importer.fileName)
// the DataImporter instance for the importer property has now been created
// prints "data.txt"



var str = "Hello World in Swift Language."
Теги:
file-io

18 ответов

414
Лучший ответ

Для чтения и записи вы должны использовать место для записи, например, каталог документов. Следующий код показывает, как читать и писать простую строку. Вы можете проверить это на детской площадке.

Swift 3.x и Swift 4.0

let file = "file.txt" //this is the file. we will write to and read from it

let text = "some text" //just a text

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 */}

    //reading
    do {
        let text2 = try String(contentsOf: fileURL, encoding: .utf8)
    }
    catch {/* error handling here */}
}

Swift 2.2

let file = "file.txt" //this is the file. we will write to and read from it

let text = "some text" //just a text

if let dir = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.AllDomainsMask, true).first {
    let path = NSURL(fileURLWithPath: dir).URLByAppendingPathComponent(file)

    //writing
    do {
        try text.writeToURL(path, atomically: false, encoding: NSUTF8StringEncoding)
    }
    catch {/* error handling here */}

    //reading
    do {
        let text2 = try NSString(contentsOfURL: path, encoding: NSUTF8StringEncoding)
    }
    catch {/* error handling here */}
}

Swift 1.x

let file = "file.txt"

if let dirs : [String] = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.AllDomainsMask, true) as? [String] {
    let dir = dirs[0] //documents directory
    let path = dir.stringByAppendingPathComponent(file);
    let text = "some text"

    //writing
    text.writeToFile(path, atomically: false, encoding: NSUTF8StringEncoding, error: nil);

    //reading
    let text2 = String(contentsOfFile: path, encoding: NSUTF8StringEncoding, error: nil)
}
  • 1
    let text2 = String.stringWithContentsOfFile (path) // XCode 6.0
  • 0
    Использование этого решения работает, но если я открою файл, в нем нет текста. Я что-то пропустил?
Показать ещё 17 комментариев
77

Предполагая, что вы переместили ваш текстовый файл data.txt в ваш Xcode-проект (используйте drag'n'drop и отметьте "Копировать файлы при необходимости"), вы можете сделать следующее, как в Objective-C:

let bundle = NSBundle.mainBundle()
let path = bundle.pathForResource("data", ofType: "txt")        
let content = NSString.stringWithContentsOfFile(path) as String

println(content) // prints the content of data.txt

Обновить:
Для чтения файла из Bundle (iOS) вы можете использовать:

let path = NSBundle.mainBundle().pathForResource("FileName", ofType: "txt")
var text = String(contentsOfFile: path!, encoding: NSUTF8StringEncoding, error: nil)!
println(text)

Обновление для Swift 3:

let path = Bundle.main.path(forResource: "data", ofType: "txt") // file path for file "data.txt"
var text = String(contentsOfFile: path!, encoding: NSUTF8StringEncoding, error: nil)!
  • 3
    Для проектов iOS «stringWithContentsOfFile» недоступен (не рекомендуется для iOS 7)
  • 0
    Ничего общего с проектами iOS, он устарел и больше не работает с Xcode 6.1 (включая Mac OS X)
Показать ещё 3 комментария
68

Xcode 8.x • Swift 3.x или новее

do {
    // get the documents folder url
    if let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
        // create the destination url for the text file to be saved
        let fileURL = documentDirectory.appendingPathComponent("file.txt")
        // define the string/text to be saved
        let text = "Hello World !!!"
        // writing to disk 
        // Note: if you set atomically to true it will overwrite the file if it exists without a warning
        try text.write(to: fileURL, atomically: false, encoding: .utf8)
        print("saving was successful")
        // any posterior code goes here
        // reading from disk
        let savedText = try String(contentsOf: fileURL)
        print("savedText:", savedText)   // "Hello World !!!\n"
    }
} catch {
    print("error:", error)
}
  • 2
    чистый, компилирует
  • 0
    Что является наиболее распространенными ошибками «Нет такого файла». Поскольку я добавил свои .txt файлы в навигатор проекта, а затем я пытаюсь открыть их, я получаю это сообщение. (Создайте их на рабочем столе и перетащите их в навигатор проекта)
50

Новый более простой и рекомендуемый метод: Apple рекомендует использовать URL для обработки файлов, и приведенные выше решения кажутся устаревшими (см. Комментарии ниже). Ниже приведен новый простой способ чтения и записи с помощью URL (не забывайте обрабатывать возможные ошибки URL):

Swift 4.0 и 3.1

import Foundation  // Needed for those pasting into Playground

let fileName = "Test"
let dir = try? FileManager.default.url(for: .documentDirectory, 
      in: .userDomainMask, appropriateFor: nil, create: true)

// If the directory was found, we write a file to it and read it back
if let fileURL = dir?.appendingPathComponent(fileName).appendingPathExtension("txt") {

    // Write to the file named Test
    let outString = "Write this text to the file"
    do {
        try outString.write(to: fileURL, atomically: true, encoding: .utf8)
    } catch {
        print("Failed writing to URL: \(fileURL), Error: " + error.localizedDescription)
    }

    // Then reading it back from the file
    var inString = ""
    do {
        inString = try String(contentsOf: fileURL)
    } catch {
        print("Failed reading from URL: \(fileURL), Error: " + error.localizedDescription)
    }
    print("Read from the file: \(inString)")
}
  • 0
    Можете ли вы предоставить ссылку, где Apple рекомендует такой способ. Или вы можете подробнее рассказать, почему это рекомендуемый способ?
  • 5
    @Andrej "Объекты URL являются предпочтительным способом обращения к локальным файлам. Большинство объектов, которые считывают данные или записывают данные в файл, имеют методы, которые принимают объект NSURL вместо пути в качестве ссылки на файл." developer.apple.com/library/ios/documentation/Cocoa/Reference/...
Показать ещё 6 комментариев
25

Xcode 8, Swift 3 способ чтения файла из пакета приложений:

if let path = Bundle.main.path(forResource: filename, ofType: nil) {
    do {
        let text = try String(contentsOfFile: path, encoding: String.Encoding.utf8)
        print(text)
    } catch {
        printError("Failed to read text from \(filename)")
    }
} else {
    printError("Failed to load file from app bundle \(filename)")
} 

Здесь удобная копия и вставка Extension

public extension String {
    func contentsOrBlank()->String {
        if let path = Bundle.main.path(forResource:self , ofType: nil) {
            do {
                let text = try String(contentsOfFile:path, encoding: String.Encoding.utf8)
                return text
                } catch { print("Failed to read text from bundle file \(self)") }
        } else { print("Failed to load file from bundle \(self)") }
        return ""
    }
    }

Например

let t = "yourFile.txt".contentsOrBlank()

Вы почти всегда хотите массив строк:

let r:[String] = "yourFile.txt"
     .contentsOrBlank()
     .characters
     .split(separator: "\n", omittingEmptySubsequences:ignore)
     .map(String.init)
  • 2
    Я вставил в удобное расширение @crashalot - не стесняйтесь, ура
  • 1
    отправил награду за фантастический ответ, ура @crashalot
Показать ещё 3 комментария
10

Я хочу показать вам только первую часть, то есть прочитать. Вот как просто вы можете читать:

Swift 3:

let s = try String(contentsOfFile: Bundle.main.path(forResource: "myFile", ofType: "txt")!)

Swift 2:

let s = try! String(contentsOfFile: NSBundle.mainBundle().pathForResource("myFile", ofType: "txt")!)
  • 0
    не забудьте добавить: сделать {..код выше ..} catch {}
3

В текущем принятом ответе выше от Адама были некоторые ошибки для меня, но вот как я переработал его ответ и сделал эту работу для меня.

let file = "file.txt"

let dirs: [String]? = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.AllDomainsMask, true) as? [String]

if (dirs != nil) {
    let directories:[String] = dirs!
    let dirs = directories[0]; //documents directory
    let path = dirs.stringByAppendingPathComponent(file);
    let text = "some text"

    //writing
    text.writeToFile(path, atomically: false, encoding: NSUTF8StringEncoding, error: nil);

    //reading
     var error:NSError?

    //reading
    let text2 = String(contentsOfFile: path, encoding:NSUTF8StringEncoding, error: &error)

    if let theError = error {
        print("\(theError.localizedDescription)")
    }
}
2

Самый простой способ прочитать файл в Swift> 4.0

 let path = Bundle.main.path(forResource: "data", ofType: "txt") // file path for file "data.txt"
        do {
            var text = try String(contentsOfFile: path!)
        }
        catch(_){print("error")}
    }
2

Последний код swift3
Вы можете читать данные из текстового файла, просто используя следующий код Этот текстовый файл

     {
"NumberOfSlices": "8",
"NrScenes": "5",
"Scenes": [{
           "dataType": "label1",
           "image":"http://is3.mzstatic.com/image/thumb/Purple19/v4/6e/81/31/6e8131cf-2092-3cd3-534c-28e129897ca9/mzl.syvaewyp.png/53x53bb-85.png",

           "value": "Hello",
           "color": "(UIColor.red)"
           }, {
           "dataType": "label2",
           "image":"http://is1.mzstatic.com/image/thumb/Purple71/v4/6c/4c/c1/6c4cc1bc-8f94-7b13-f3aa-84c41443caf3/mzl.hcqvmrix.png/53x53bb-85.png",
           "value": "Hi There",
           "color": "(UIColor.blue)"
           }, {
           "dataType": "label3",
           "image":"http://is1.mzstatic.com/image/thumb/Purple71/v4/6c/4c/c1/6c4cc1bc-8f94-7b13-f3aa-84c41443caf3/mzl.hcqvmrix.png/53x53bb-85.png",

           "value": "hi how r u ",
           "color": "(UIColor.green)"
           }, {
           "dataType": "label4",
           "image":"http://is1.mzstatic.com/image/thumb/Purple71/v4/6c/4c/c1/6c4cc1bc-8f94-7b13-f3aa-84c41443caf3/mzl.hcqvmrix.png/53x53bb-85.png",
           "value": "what are u doing  ",
           "color": "(UIColor.purple)"
           }, {
           "dataType": "label5",
          "image":"http://is1.mzstatic.com/image/thumb/Purple71/v4/6c/4c/c1/6c4cc1bc-8f94-7b13-f3aa-84c41443caf3/mzl.hcqvmrix.png/53x53bb-85.png",
           "value": "how many times ",
           "color": "(UIColor.white)"
           }, {
           "dataType": "label6",
           "image":"http://is1.mzstatic.com/image/thumb/Purple71/v4/5a/f3/06/5af306b0-7cac-1808-f440-bab7a0d18ec0/mzl.towjvmpm.png/53x53bb-85.png",
           "value": "hi how r u ",
           "color": "(UIColor.blue)"
           }, {
           "dataType": "label7",
           "image":"http://is5.mzstatic.com/image/thumb/Purple71/v4/a8/dc/eb/a8dceb29-6daf-ca0f-d037-df9f34cdc476/mzl.ukhhsxik.png/53x53bb-85.png",
           "value": "hi how r u ",
           "color": "(UIColor.gry)"
           }, {
           "dataType": "label8",
           "image":"http://is2.mzstatic.com/image/thumb/Purple71/v4/15/23/e0/1523e03c-fff2-291e-80a7-73f35d45c7e5/mzl.zejcvahm.png/53x53bb-85.png",
           "value": "hi how r u ",
           "color": "(UIColor.brown)"
           }]

}

Вы можете использовать этот код для получения данных из текстового json файла в swift3

     let filePath = Bundle.main.path(forResource: "nameoftheyourjsonTextfile", ofType: "json")


    let contentData = FileManager.default.contents(atPath: filePath!)
    let content = NSString(data: contentData!, encoding: String.Encoding.utf8.rawValue) as? String

    print(content)
    let json = try! JSONSerialization.jsonObject(with: contentData!) as! NSDictionary
    print(json)
    let app = json.object(forKey: "Scenes") as! NSArray!
    let _ : NSDictionary
    for dict in app! {
        let colorNam = (dict as AnyObject).object(forKey: "color") as! String
        print("colors are \(colorNam)")

       // let colour = UIColor(hexString: colorNam) {
       // colorsArray.append(colour.cgColor)
       // colorsArray.append(colorNam  as! UIColor)

        let value = (dict as AnyObject).object(forKey: "value") as! String
        print("the values are \(value)")
        valuesArray.append(value)

        let images = (dict as AnyObject).object(forKey: "image") as! String
        let url = URL(string: images as String)
        let data = try? Data(contentsOf: url!)
        print(data)
        let image1 = UIImage(data: data!)! as UIImage
        imagesArray.append(image1)
         print(image1)
            }
2

Для моего txt файла работает следующим образом:

let myFileURL = NSBundle.mainBundle().URLForResource("listacomuni", withExtension: "txt")!
let myText = try! String(contentsOfURL: myFileURL, encoding: NSISOLatin1StringEncoding)
print(String(myText))
2

В примере функции (read | write) DocumentsFromFile (...) с некоторыми оболочками функций, безусловно, имеет смысл, поскольку все в OSx и iOS, кажется, нуждается в трех или четырех основных классах, созданных экземпляром, и куча свойств, настроенных, связанный, созданный экземпляр и набор, просто чтобы написать "Привет" в файл в 182 странах.

Однако эти примеры недостаточно полны для использования в реальной программе. Функция записи не сообщает о каких-либо ошибках при создании или записи в файл. При чтении я не думаю, что было бы неплохо вернуть ошибку, чтобы файл не существовал как строка, которая должна содержать данные, которые были прочитаны. Вы хотели бы знать, что это не удалось, и почему через какой-либо механизм уведомления, как исключение. Затем вы можете написать код, который выводит проблему, и позволяет пользователю ее исправлять или "правильно" разрывает программу в этой точке.

Вы не хотели бы просто возвращать строку, в которой "Файл ошибки не существует". Затем вам придется искать ошибку в строке из вызывающей функции каждый раз и обрабатывать ее там. Вы также, возможно, не могли действительно определить, действительно ли строка ошибки была прочитана из фактического файла или если она была создана из вашего кода.

Вы даже не можете вызвать чтение, как это, в swift 2.2 и Xcode 7.3, потому что NSString (contentsOfFile...) генерирует исключение. Это ошибка времени компиляции, если у вас нет кода, чтобы поймать его и что-то сделать с ним, например, распечатать его на stdout или, лучше, всплывающее окно с ошибкой или stderr. Я слышал, что Apple уходит от try catch и исключений, но это будет длинный ход, и без него невозможно писать код. Я не знаю, откуда приходит аргумент & ошибка, возможно, более старая версия, но NSString.writeTo [File | URL] в настоящее время не имеет аргумента NSError. Они определены следующим образом: NSString.h:

public func writeToURL(url: NSURL, atomically useAuxiliaryFile: Bool, encoding enc: UInt) throws
public func writeToFile(path: String, atomically useAuxiliaryFile: Bool, encoding enc: UInt) throws
public convenience init(contentsOfURL url: NSURL, encoding enc: UInt) throws
public convenience init(contentsOfFile path: String, encoding enc: UInt) throws

Кроме того, файл, не существующий, является лишь одним из нескольких потенциальных проблем, которые ваша программа могла бы прочитать в файле, например, проблема с разрешениями, размер файла или множество других проблем, которые вы даже не захотите пытаться выполнить код обработчик для каждого из них. Лучше всего предположить, что все правильно, и поймать, и распечатать или обработать исключение, если что-то пойдет не так, к тому же на данный момент у вас действительно нет выбора.

Вот мои перезаписи:

func writeToDocumentsFile(fileName:String,value:String) {

    let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString!
    let path = documentsPath.stringByAppendingPathComponent(fileName)

    do {
        try value.writeToFile(path, atomically: true, encoding: NSUTF8StringEncoding)
    } catch let error as NSError {
        print("ERROR : writing to file \(path) : \(error.localizedDescription)")
    }

}

func readFromDocumentsFile(fileName:String) -> String {

    let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString
    let path = documentsPath.stringByAppendingPathComponent(fileName)

    var readText : String = ""

    do {
        try readText = NSString(contentsOfFile: path, encoding: NSUTF8StringEncoding) as String
    }
    catch let error as NSError {
        print("ERROR : reading from file \(fileName) : \(error.localizedDescription)")
    }
    return readText
}
  • 0
    Я думаю, что во многих ваших ответах вы не понимаете мою точку зрения. (или вам может быть все равно, и это нормально). Однако, чтобы быть понятным, генерировать исключение и как-то обрабатывать его, когда вы ищете файл, которого там нет (или имеет другую проблему, такую как разрешение), гораздо лучше, чем возвращать строку, например "ОШИБКА: Файл [имя файла] не существует "как строка, которую вы должны были на самом деле прочитать из файла. Тогда просто печатать это. Во всяком случае, вы должны напечатать подробности об исключении, а не о том, что не удалось прочитать строку, в которой теперь есть ошибка. Программа, вероятно, не должна просто продолжаться.
2

Мне пришлось перекодировать вот так:

let path = NSBundle.mainBundle().pathForResource("Output_5", ofType: "xml")
let text = try? NSString(contentsOfFile: path! as String, encoding: NSUTF8StringEncoding)
print(text)
2

Вы можете найти этот инструмент полезным не только для чтения из файла в Swift, но и для синтаксического анализа ваших данных: https://github.com/shoumikhin/StreamScanner

Просто укажите путь к файлу и разделители данных следующим образом:

import StreamScanner

if let input = NSFileHandle(forReadingAtPath: "/file/path")
{
    let scanner = StreamScanner(source: input, delimiters: NSCharacterSet(charactersInString: ":\n"))  //separate data by colons and newlines

    while let field: String = scanner.read()
    {
        //use field
    }
}

Надеюсь, это поможет.

2

Чтобы избежать путаницы и облегчения, я создал две функции для чтения и записи строк в файлы в каталоге документов. Вот функции:

func writeToDocumentsFile(fileName:String,value:String) {
    let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as! NSString
    let path = documentsPath.stringByAppendingPathComponent(fileName)
    var error:NSError?
    value.writeToFile(path, atomically: true, encoding: NSUTF8StringEncoding, error: &error)
}

func readFromDocumentsFile(fileName:String) -> String {
    let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as! NSString
    let path = documentsPath.stringByAppendingPathComponent(fileName)
    var checkValidation = NSFileManager.defaultManager()
    var error:NSError?
    var file:String

    if checkValidation.fileExistsAtPath(path) {
        file = NSString(contentsOfFile: path, encoding: NSUTF8StringEncoding, error: nil) as! String
    } else {
        file = "*ERROR* \(fileName) does not exist."
    }

    return file
}

Вот пример их использования:

writeToDocumentsFile("MyText.txt","Hello world!")

let value = readFromDocumentsFile("MyText.txt")
println(value)  //Would output 'Hello world!'

let otherValue = readFromDocumentsFile("SomeText.txt")
println(otherValue)  //Would output '*ERROR* SomeText.txt does not exist.'

Надеюсь, это поможет!

Версия Xcode: 6.3.2

  • 0
    В Xcode 7.3 функции не компилируются.
1

Это работает с Swift 3.1.1 в Linux:

import Foundation

let s = try! String(contentsOfFile: "yo", encoding: .utf8)
1

записать в ViewDidLoad

var error: NSError?
var paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
var documentsDirectory = paths.first as String
var dataPath = documentsDirectory.stringByAppendingPathComponent("MyFolder")

if !NSFileManager.defaultManager().fileExistsAtPath(dataPath) {
    NSFileManager.defaultManager().createDirectoryAtPath(dataPath, withIntermediateDirectories: false, attributes: nil, error: &error)
} else {
    println("not creted or exist")
}

func listDocumentDirectoryfiles() -> [String] {
    if let documentDirectory = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first as? String {
        let myFilePath = documentDirectory.stringByAppendingPathComponent("MyFolder")
        return NSFileManager.defaultManager().contentsOfDirectoryAtPath(myFilePath, error: nil) as [String]
    }
    return []
}
0

Xcode 8.3.2 Swift 3.x. Использование NSKeyedArchiver и NSKeyedUnarchiver

Чтение файла из документов

let documentsDirectoryPathString = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
let documentsDirectoryPath = NSURL(string: documentsDirectoryPathString)!
let jsonFilePath = documentsDirectoryPath.appendingPathComponent("Filename.json")

let fileManager = FileManager.default
var isDirectory: ObjCBool = false

if fileManager.fileExists(atPath: (jsonFilePath?.absoluteString)!, isDirectory: &isDirectory) {

let finalDataDict = NSKeyedUnarchiver.unarchiveObject(withFile: (jsonFilePath?.absoluteString)!) as! [String: Any]
}
else{
     print("File does not exists")
}

Запись файла в документы

NSKeyedArchiver.archiveRootObject(finalDataDict, toFile:(jsonFilePath?.absoluteString)!)
0
 func writeToDocumentsFile(fileName:String,value:String) {
    let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString
    let path = documentsPath.appendingPathComponent(fileName)
    do{
    try value.write(toFile: path, atomically: true, encoding: String.Encoding.utf8)
}catch{
    }
    }

func readFromDocumentsFile(fileName:String) -> String {
    let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString
    let path = documentsPath.appendingPathComponent(fileName)
    let checkValidation = FileManager.default
    var file:String

    if checkValidation.fileExists(atPath: path) {
        do{
       try file = NSString(contentsOfFile: path, encoding: String.Encoding.utf8.rawValue) as String
        }catch{
            file = ""
        }
        } else {
        file = ""
    }

    return file
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню