Я работал с формой кода этот ответ, предоставленный Мартином Р. Код является удивительным, и это очень полезно. Однако он не работает со ссылками, отлично работает с файлами. После размещения некоторых NSLogs и разрывов я действительно обнаружил, что проблема заключается в этом кодовом блоке:
init?(path: String, delimiter: String = "\n", encoding: UInt = NSUTF8StringEncoding, chunkSize : Int = 4096) {
self.chunkSize = chunkSize
self.encoding = encoding
self.fileHandle = NSFileHandle(forReadingFromURL: NSURL(string: path)!, error: nil)
println("PATH IS \(path)")
println("FILE HANDLE IS \(fileHandle)")
if self.fileHandle == nil {
println("FILE HANDLE IS NIL!")
return nil
}
В приведенном выше коде фактически содержатся некоторые незначительные изменения по сравнению с ответом Мартина. Также Apple говорит, что можно использовать fileHandle с forReadingFromURL, и он не должен возвращать нуль. Но вот консольный вывод:
PATH IS http://smth.com
FILE HANDLE IS nil
FILE HANDLE IS NIL!!!!!
Вопрос в том, что неправильно?
UPDATE
Как любезно объяснил мне Martin R, этот код не будет работать с URL-адресами, этот ответ утверждает то же самое, поэтому я переписал код, руководствуясь предыдущие ответы:
import Foundation
import Cocoa
class StreamReader {
let encoding : UInt
let chunkSize : Int
var atEof : Bool = false
var streamData : NSData!
var fileLength : Int
var urlRequest : NSMutableURLRequest
var currentOffset : Int
var streamResponse : NSString
var fileHandle : NSFileHandle!
let buffer : NSMutableData!
let delimData : NSData!
var reponseError: NSError?
var response: NSURLResponse?
init?(path: NSURL, delimiter: String = "\n", encoding: UInt = NSUTF8StringEncoding, chunkSize : Int = 10001000) {
println("YOUR PATH IS \(path)")
self.chunkSize = chunkSize
self.encoding = encoding
self.currentOffset = 0
urlRequest = NSMutableURLRequest(URL: path)
streamData = NSURLConnection.sendSynchronousRequest(urlRequest, returningResponse:&response, error:&reponseError)
streamResponse = NSString(data:streamData!, encoding:NSUTF8StringEncoding)!
self.fileLength = streamData.length
//println("WHAT IS STREAMDATA \(streamData)")
//println("WHAT IS URLREQUEST \(urlRequest)")
if streamData == nil {
println("LINK HAS NO CONTENT!!!!!")
}
self.fileLength = streamResponse.length
println("FILE LENGTH IS \(fileLength)")
self.buffer = NSMutableData(capacity: chunkSize)!
// Create NSData object containing the line delimiter:
delimData = delimiter.dataUsingEncoding(NSUTF8StringEncoding)!
println("WHAT DOES THE DELIMITER \(delimiter)LOOK LIKE?")
println("WHAT IS DELIMDATA \(delimData)")
}
deinit {
self.close()
}
/// Return next line, or nil on EOF.
func nextLine() -> String? {
if atEof {
println("AT THE END OF YOUR FILE!!!")
return nil
}
// Read data chunks from file until a line delimiter is found:
if currentOffset >= fileLength {
return nil
}
var blockLength : Int = buffer.length
var range = buffer.rangeOfData(delimData, options: NSDataSearchOptions(0), range: NSMakeRange(currentOffset, blockLength))
//println("STREAM DATA \(streamData)")
println("RANGE IS \(range)")
while range.location == NSNotFound {
var nRange = NSMakeRange(currentOffset, chunkSize)
println("nRange is \(nRange)")
var tmpData = streamData.subdataWithRange(nRange)
//println("TMP data length \(tmpData.length)")
currentOffset += blockLength
//println("TMPDATA is \(tmpData)")
if tmpData.length == 0 {
// EOF or read error.
println("ERROR ????")
atEof = true
if buffer.length > 0 {
// Buffer contains last line in file (not terminated by delimiter).
let line = NSString(data: buffer, encoding: encoding);
buffer.length = 0
println("THE LINE IS \(line)")
return line
}
// No more lines.
return nil
}
buffer.appendData(tmpData)
range = buffer.rangeOfData(delimData, options: NSDataSearchOptions(0), range: NSMakeRange(0, buffer.length))
}
// Convert complete line (excluding the delimiter) to a string:
let line = NSString(data: buffer.subdataWithRange(NSMakeRange(0, range.location)),
encoding: encoding)
// Remove line (and the delimiter) from the buffer:
buffer.replaceBytesInRange(NSMakeRange(0, range.location + range.length), withBytes: nil, length: 0)
return line
}
/// Start reading from the beginning of file.
func rewind() -> Void {
//streamData.seekToFileOffset(0)
buffer.length = 0
atEof = false
}
/// Close the underlying file. No reading must be done after calling this method.
func close() -> Void {
if streamData != nil {
streamData = nil
}
}
}
extension StreamReader : SequenceType {
func generate() -> GeneratorOf<String> {
return GeneratorOf<String> {
return self.nextLine()
}
}
}
Но на самом деле этот код очень далек от совершенства, и я хотел бы видеть какие-либо рекомендации по его улучшению. Пожалуйста, будь добр. Я очень любитель и очень неопытен (но рано или поздно я узнаю его)
Наконец, он работает. И, вероятно, последняя проблема остается, код не останавливается, он продолжает читать файл с самого начала.
Итак, теперь вопрос, вероятно, ближе к "Что не так с моим кодом?", по сравнению с предыдущим: "Что не так?"
UPDATE
Я переписал последние части кода следующим образом:
let line = NSString(data: buffer.subdataWithRange(NSMakeRange(0, range.location + 1)),
encoding: encoding)
buffer.replaceBytesInRange(NSMakeRange(0, range.location + range.length), withBytes: nil, length: 0)
println("COMPLETE LINE IS \(line)")
if line!.containsString("\n"){
println("CONTAINS NEW LINE")
//println("BUFFER IS \(buffer)")
//
println("COMPLETE LINE IS \(line)")
return line
}
else {
println("NO LINE!")
atEof == true
return nil
}
Идея состоит в том, чтобы пройти через все строки, содержащие \n
, и исключить одну строку, которая является последней, и не должна иметь \n
. Но! Несмотря на то, что я проверил непечатаемые символы и не было \n
, вот удивительный вывод консоли: Optional("lastline_blablabla\n")
Вероятно, теперь вопрос в том, как остановиться на последней строке, даже если она содержит \n
?
Если вам нужно получить данные из URL-адреса, мой код выше (тот, который находится под первым обновлением), будет работать
Но моя собственная проблема с \n
имеет несколько способов решения. Один из них я использовал в своем коде. Поскольку это очень индивидуально, я не буду публиковать решение для \n
в конце проблемы с файлом. Кроме того, я не уверен, что мои оба решения для urlStreamReader
и \n
являются лучшими, поэтому, если вы посоветуете какое-либо лучшее решение, это будет оценено мной и, возможно, некоторыми другими людьми.
Большое спасибо Мартину Р, который многое объяснил, написал отличный код и был очень приятным