如何在Swift中从文件(而不是整个文件)中读取数据块

时间:2019-04-27 19:56:48

标签: swift

假设我有一个8字节长的文件,仅包含ASCII字符:brownfox

我不会加载整个文件并处理if,我不会加载2个字节的[UInt8]块,而是对2个字节大小的块进行操作,因此操作如下:

  1. 从文件中加载br(而不是整个文件)
  2. 对数据执行任何操作,例如反转到rb
  3. 将输出保存到另一个文件
  4. 重复以下内容:ow nf ox

背后的原因: 这样,如果我处理的文件是1GB的文本,我实际上并没有1GB的可用RAM(对于输入和输出文件则为2GB)。

这种文件处理方法对我来说很重要,对于加密并发送到云解决方案来说

我正在使用此扩展程序:

extension Data {
    /**
     Consumes the specified input stream, creating a new Data object
     with its content.
     - Parameter reading: The input stream to read data from.
     - Note: Closes the specified stream.
     */
    init(reading input: InputStream) {
        self.init()
        input.open()

        let bufferSize = 1024
        let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize)
        while input.hasBytesAvailable {
            let read = input.read(buffer, maxLength: bufferSize)
            self.append(buffer, count: read)
        }
        buffer.deallocate()

        input.close()
    }

    /**
     Consumes the specified input stream for up to `byteCount` bytes,
     creating a new Data object with its content.
     - Parameter reading: The input stream to read data from.
     - Parameter byteCount: The maximum number of bytes to read from `reading`.
     - Note: Does _not_ close the specified stream.
     */
    init(reading input: InputStream, for byteCount: Int) {
        self.init()
        input.open()

        let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: byteCount)
        let read = input.read(buffer, maxLength: byteCount)
        self.append(buffer, count: read)
        buffer.deallocate()
    }
}

但是init(reading input: InputStream, for byteCount: Int)总是从第1个字节开始。例如,如何读取第16到20个字节?

InputStream.read(_:maxLength:)上的文档

  

从当前的读取索引开始,占用指定的字节数   在流中的第二个参数中并将其放置在   客户端提供的缓冲区(第一个参数)。缓冲区必须是   第二个参数指定的大小。返回实际数量   放置在缓冲区中的字节;如果流中什么也没剩下,   返回0。将索引重置到流中以进行下一个读取操作。

我该怎么办重置索引,并从上一个结束的地方进行下一个操作?

2 个答案:

答案 0 :(得分:1)

使用FileHandle。您可以打开文件句柄进行读取。然后使用seek(toFileOffset:)设置您要读取的位置。然后使用readData(ofLength:)得到一些Data。完成后请确保关闭文件句柄。

答案 1 :(得分:0)

rmaddy的解决方案成功了!

对于任何遇到同样问题的人来说,这都是一个非常粗糙的片段。这不是一个确切的答案,但它显示了需要完成的所有操作:)

    func loadInBlocks(path: String) -> [Data] {
        var blocks = [Data]()
        let correctPath = //path to file
        let fileHandle = FileHandle(forReadingAtPath: correctPath)

        let dataFromFirstByteTo4thByte = fileHandle!.readData(ofLength: 4)
        blocks.append(dataFromFirstByteTo4thByte)
        fileHandle?.seek(toFileOffset: 4)
        let dataFrom5thByteTo8thByte = fileHandle!.readData(ofLength: 4)
        blocks.append(dataFrom5thByteTo8thByte)
        fileHandle?.closeFile()

        return blocks
    }

和实际用法:

    func loadBlock(number: Int, withBlockSize size: Int, path: String) throws -> Data {
        let correctPath = path.replacingOccurrences(of: "file://", with: "").replacingOccurrences(of: "%20", with: " ")

        guard let fileHandle = FileHandle(forReadingAtPath: correctPath) else { throw NSError() }

        let bytesOffset = UInt64((number-1) * size)
        fileHandle.seek(toFileOffset: bytesOffset)
        let data = fileHandle.readData(ofLength: size)
        fileHandle.closeFile()
        return data
    }