从远程位置检索文件

时间:2017-12-22 13:38:55

标签: ios swift

我有这个代码从本地目录读取epub文件并向用户显示电子书。我希望能够从远程位置读取epub文件。有人可以指出我如何做到这一点的正确方向?我需要更改的功能是 readEpub 以及它调用的函数。谢谢!

  /**
     Unzip, delete and read an epub file.
     Returns a FRBook.
     */
    func readEpub(epubPath withEpubPath: String, removeEpub: Bool = true, unzipPath: String? = nil) throws -> FRBook? {
        epubPathToRemove = withEpubPath
        shouldRemoveEpub = removeEpub

        var isDir: ObjCBool = false
        let fileManager = FileManager.default
        let bookName = (withEpubPath as NSString).lastPathComponent

        if let path = unzipPath, (fileManager.fileExists(atPath: path) == true) {
            bookBasePath = path
        } else {
            bookBasePath = kApplicationDocumentsDirectory
        }

        bookBasePath = (bookBasePath as NSString).appendingPathComponent(bookName)

        guard fileManager.fileExists(atPath: withEpubPath) else {
            throw FolioReaderError(kind: .BookNotAvailable)
        }

        // Unzip if necessary
        var needsUnzip = false
        if fileManager.fileExists(atPath: bookBasePath, isDirectory:&isDir) {
            if !isDir.boolValue { needsUnzip = true }
        } else {
            needsUnzip = true
        }

        if needsUnzip {
            SSZipArchive.unzipFile(atPath: withEpubPath, toDestination: bookBasePath, delegate: self)
        }

        // Skip from backup this folder
        addSkipBackupAttributeToItemAtURL(URL(fileURLWithPath: bookBasePath, isDirectory: true))

        self.book.name = bookName
        try readContainer()
        try readOpf()
        return self.book
    }

    /**
     Read and parse container.xml file.
     */
    fileprivate func readContainer() throws {
        let containerPath = "META-INF/container.xml"
        do {
            let containerData = try Data(contentsOf: URL(fileURLWithPath: (bookBasePath as NSString).appendingPathComponent(containerPath)), options: .alwaysMapped)
            let xmlDoc = try AEXMLDocument(xml: containerData)
            let opfResource = FRResource()
            opfResource.href = xmlDoc.root["rootfiles"]["rootfile"].attributes["full-path"]
            opfResource.mediaType = FRMediaType.determineMediaType(xmlDoc.root["rootfiles"]["rootfile"].attributes["full-path"]!)
            book.opfResource = opfResource
            resourcesBasePath = (bookBasePath as NSString).appendingPathComponent((book.opfResource.href as NSString).deletingLastPathComponent)

        } catch {
            throw FolioReaderError(kind : .ErrorInContainer)
        }
    }

    /**
     Read and parse .opf file.
     */
    fileprivate func readOpf() throws {
        let opfPath = (bookBasePath as NSString).appendingPathComponent(book.opfResource.href)
        var identifier: String?

        do {
            let opfData = try Data(contentsOf: URL(fileURLWithPath: opfPath), options: .alwaysMapped)
            let xmlDoc = try AEXMLDocument(xml: opfData)

            // Base OPF info
            if let package = xmlDoc.children.first {
                identifier = package.attributes["unique-identifier"]

                if let version = package.attributes["version"] {
                    book.version = Double(version)
                }
            }

            // Parse and save each "manifest item"
            for item in xmlDoc.root["manifest"]["item"].all! {
                let resource = FRResource()
                resource.id = item.attributes["id"]
                resource.properties = item.attributes["properties"]
                resource.href = item.attributes["href"]
                resource.fullHref = (resourcesBasePath as NSString).appendingPathComponent(resource.href).removingPercentEncoding
                resource.mediaType = FRMediaType.mediaTypeByName(item.attributes["media-type"]!, fileName: resource.href)
                resource.mediaOverlay = item.attributes["media-overlay"]

                // if a .smil file is listed in resources, go parse that file now and save it on book model
                if (resource.mediaType != nil && resource.mediaType == FRMediaType.SMIL) {
                    readSmilFile(resource)
                }

                book.resources.add(resource)
            }

            book.smils.basePath = resourcesBasePath

            // Read metadata
            book.metadata = readMetadata(xmlDoc.root["metadata"].children)

            // Read the book unique identifier
            if let uniqueIdentifier = book.metadata.findIdentifierById(identifier) {
                book.uniqueIdentifier = uniqueIdentifier
            }

            // Read the cover image
            let coverImageId = book.metadata.findMetaByName("cover")
            if let coverResource = book.resources.findById(coverImageId) {
                book.coverImage = coverResource
            } else if let coverResource = book.resources.findByProperty("cover-image") {
                book.coverImage = coverResource
            }

            // Specific TOC for ePub 2 and 3
            // Get the first resource with the NCX mediatype
            if let tocResource = book.resources.findByMediaType(FRMediaType.NCX) {
                book.tocResource = tocResource
            } else if let tocResource = book.resources.findByExtension(FRMediaType.NCX.defaultExtension) {
                // Non-standard books may use wrong mediatype, fallback with extension
                book.tocResource = tocResource
            } else if let tocResource = book.resources.findByProperty("nav") {
                book.tocResource = tocResource
            }

            assert(book.tocResource != nil, "ERROR: Could not find table of contents resource. The book don't have a TOC resource.")

            // The book TOC
            book.tableOfContents = findTableOfContents()
            book.flatTableOfContents = createFlatTOC()

            // Read Spine
            let spine = xmlDoc.root["spine"]
            book.spine = readSpine(spine.children)

            // Page progress direction `ltr` or `rtl`
            if let pageProgressionDirection = spine.attributes["page-progression-direction"] {
                book.spine.pageProgressionDirection = pageProgressionDirection
            }
        } catch {
            throw FolioReaderError(kind: .ErrorInOpf)
        }
    }

    /**
     Reads and parses a .smil file
     */
    fileprivate func readSmilFile(_ resource: FRResource) {
        do {
            let smilData = try Data(contentsOf: URL(fileURLWithPath: resource.fullHref), options: .alwaysMapped)
            var smilFile = FRSmilFile(resource: resource)
            let xmlDoc = try AEXMLDocument(xml: smilData)

            let children = xmlDoc.root["body"].children

            if children.count > 0 {
                smilFile.data.append(contentsOf: readSmilFileElements(children))
            }

            book.smils.add(smilFile)
        } catch {
            print("Cannot read .smil file: "+resource.href)
        }
    }

    fileprivate func readSmilFileElements(_ children:[AEXMLElement]) -> [FRSmilElement] {
        var data = [FRSmilElement]()

        // convert each smil element to a FRSmil object
        for item in children {

            let smil = FRSmilElement(name: item.name, attributes: item.attributes)

            // if this element has children, convert them to objects too
            if item.children.count > 0 {
                smil.children.append(contentsOf: readSmilFileElements(item.children))
            }

            data.append(smil)
        }

        return data
    }

    /**
     Read and parse the Table of Contents.
     */
    fileprivate func findTableOfContents() -> [FRTocReference] {
        var tableOfContent = [FRTocReference]()
        var tocItems: [AEXMLElement]?
        guard let tocResource = book.tocResource else { return tableOfContent }
        let tocPath = (resourcesBasePath as NSString).appendingPathComponent(tocResource.href)

        do {
            if tocResource.mediaType == FRMediaType.NCX {
                let ncxData = try Data(contentsOf: URL(fileURLWithPath: tocPath), options: .alwaysMapped)
                let xmlDoc = try AEXMLDocument(xml: ncxData)
                if let itemsList = xmlDoc.root["navMap"]["navPoint"].all {
                    tocItems = itemsList
                }
            } else {
                let tocData = try Data(contentsOf: URL(fileURLWithPath: tocPath), options: .alwaysMapped)
                let xmlDoc = try AEXMLDocument(xml: tocData)

                if let nav = xmlDoc.root["body"]["nav"].first, let itemsList = nav["ol"]["li"].all {
                    tocItems = itemsList
                } else if let nav = findNavTag(xmlDoc.root["body"]), let itemsList = nav["ol"]["li"].all {
                    tocItems = itemsList
                }
            }
        } catch {
            print("Cannot find Table of Contents.")
        }

        guard let items = tocItems else { return tableOfContent }

        for item in items {
            tableOfContent.append(readTOCReference(item))
        }

        return tableOfContent
    }

0 个答案:

没有答案