服务器URL的streamReader

时间:2014-10-31 11:57:04

标签: swift null filehandle

我一直在使用由Martin R提供的代码形式this answer。代码非常棒且非常有用。但是,它不能与链接一起使用,同时可以正常处理文件。在放入一些NSLog和中断之后,我实际上发现问题出现在这个代码块中:

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
    }

与Martin的回答相比,上面的代码实际上包含了一些细微的变化。另外Apple says可以将fileHandle与forReadingFromURL一起使用,并且它不应该返回nil。  但这是控制台输出:

PATH IS http://smth.com
   FILE HANDLE IS nil
   FILE HANDLE IS NIL!!!!!

问题是什么错了?

更新

正如Martin R向我解释的那样,这段代码不能使用URL,this answer说明相同的内容,所以我重写了代码,引用了之前的答案:

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()
    }
}
}

但实际上这段代码远非完美,我希望看到有关改进它的任何建议。请善待。我非常业余,非常缺乏经验(但迟早我会学习它)

最后,它正在发挥作用。可能还有最后一个问题,代码不会停止,它会从头开始继续读取文件。

所以现在问题可能更接近我的代码的错误了?&#39;与以前相比:&#39;什么&#39;错了?&#39;

更新

我已经重写了这样的代码的最后部分:

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,如何停在最后一行?

如果您需要从我的代码检索上面的代码(第一次更新下的代码),

\n我自己的问题有几种方法可以解决。其中一个我在我的代码中使用过。由于它是非常个人的,我不会在文件发布结束时将解决方案发布到\n。另外,我不确定urlStreamReader\n的解决方案是否最好,所以如果您建议任何更好的解决方案,我会非常感谢其他人。

非常感谢Martin R,他解释了很多,编写了很棒的代码并且非常好

0 个答案:

没有答案