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

如何在Swift中从文件(而不是整个文件)读取数据块,swift,Swift,假设我有一个8字节长的文件,只包含ASCII字符:brownfox 我不想加载整个文件并处理if,而是想加载2字节的块[UInt8]并对2字节大小的块进行操作,因此操作如下: 从文件(而不是整个文件)加载br 对数据执行任何操作,例如反转到rb 将输出保存到另一个文件 重复以下步骤:ownfox 其背后的原因是: 这样,如果我处理的文件是1GB的文本,我实际上不必有1GB的RAM空闲(或2GB的输入和输出文件) 这种文件处理方法对于加密和发送到云解决方案对我来说很重要 我正在使用此扩展: 扩展数

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

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

  • 从文件(而不是整个文件)加载
    br
  • 对数据执行任何操作,例如反转到
    rb
  • 将输出保存到另一个文件
  • 重复以下步骤:
    ow
    nf
    ox
  • 其背后的原因是: 这样,如果我处理的文件是1GB的文本,我实际上不必有1GB的RAM空闲(或2GB的输入和输出文件)

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

    我正在使用此扩展:

    扩展数据{
    /**
    使用指定的输入流,创建新的数据对象
    与它的内容。
    -参数读取:从中读取数据的输入流。
    -注意:关闭指定的流。
    */
    初始化(读取输入:InputStream){
    self.init()
    input.open()
    让bufferSize=1024
    let buffer=unsafemeutablepointer.allocate(容量:bufferSize)
    当input.hasbytes可用时{
    让read=input.read(缓冲区,maxLength:bufferSize)
    self.append(缓冲区,计数:读取)
    }
    buffer.deallocate()
    input.close()
    }
    /**
    将指定的输入流消耗最多'byteCount'字节,
    创建包含其内容的新数据对象。
    -参数读取:从中读取数据的输入流。
    -参数byteCount:从“reading”读取的最大字节数。
    -注意:不关闭指定的流。
    */
    init(读取输入:InputStream,字节数为:Int){
    self.init()
    input.open()
    let buffer=unsafemeutablepointer.allocate(容量:字节数)
    let read=input.read(缓冲区,maxLength:byteCount)
    self.append(缓冲区,计数:读取)
    buffer.deallocate()
    }
    }
    
    但是
    init(读取输入:InputStream,字节数:Int)
    总是从第一个字节开始。例如,如何读取16到20字节

    关于
    InputStream.read(\uux:maxLength:)

    从当前读取索引中,最多占用指定的字节数 在流的第二个参数中,并将它们放置在 客户端提供的缓冲区(第一个参数)。缓冲区必须是 由第二个参数指定的大小。返回实际的 放入缓冲区的字节;如果小溪里什么都没有了, 返回0。将索引重置到流中以进行下一次读取操作


    如何才能不重置索引,并从上一个操作结束的位置获取下一个操作?

    使用
    文件句柄。您可以打开文件句柄进行读取。然后使用
    seek(toFileOffset:)
    设置要从中读取的位置。然后使用
    readData(长度:)
    获取一些
    数据。完成后请确保关闭文件句柄。

    rmaddy的解决方案有效

    这里有一个非常粗略的片段,供任何带着同样问题来到这里的人参考。这不是一个确切的答案,但它显示了需要做的一切:)

    func加载块(路径:字符串)->[数据]{
    变量块=[数据]()
    让correctPath=//文件的路径
    让fileHandle=fileHandle(用于读取路径:correctPath)
    让dataFromFirstByteTo4thByte=fileHandle!.readData(长度:4)
    blocks.append(数据从第一字节到第四字节)
    文件句柄?.seek(toFileOffset:4)
    让dataFrom5thByteTo8thByte=fileHandle!.readData(长度:4)
    blocks.append(数据从5thbyteto8thbyte)
    fileHandle?.closeFile()文件
    返回块
    }
    
    以及实际用途:

    func加载块(编号:Int,withBlockSize大小:Int,路径:String)抛出->数据{
    让correctPath=path.replacingOccurrences(of:“file://”,with:).replacingOccurrences(of:“%20”,with:”)
    guard let fileHandle=fileHandle(forReadingAtPath:correctPath)else{throw NSError()}
    let bytesOffset=UInt64((数字-1)*大小)
    查找(toFileOffset:bytesOffset)
    let data=fileHandle.readData(of长度:大小)
    fileHandle.closeFile()文件
    返回数据
    }
    
    我很确定您不需要调用
    seek
    ,因为
    readData
    移动了文件指针,您的下一次读取就到此为止。您还应该重新检查对
    nil
    的处理。您可以同时使用
    文件句柄上的
    。在这种情况下两者都不理想,但至少要保持一致。上面的代码只是概念的证明。实际代码解决了这个问题:)我做了一个编辑来展示它的样子。而且,是的,我知道,我可以做得比抛出一个通用的
    n错误更好