Skip to content

Instantly share code, notes, and snippets.

@mingsai
Last active August 2, 2021 16:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mingsai/dddce65c98753ace216c to your computer and use it in GitHub Desktop.
Save mingsai/dddce65c98753ace216c to your computer and use it in GitHub Desktop.
A Stream Reader / Writer that takes two URLs and copies from source to target without exceeding memory limits.
//
// MNGStreamReaderWriter.swift
// ths
//
// Created by Tommie N. Carter, Jr., MBA on 2/14/16.
// Copyright © 2016 MING Technology. All rights reserved.
//
import Foundation
import Darwin.Mach.mach_time
class MNGStreamReaderWriter:NSObject {
var copyOutput:NSOutputStream?
var fileInput:NSInputStream?
var outputStream:NSOutputStream? = NSOutputStream(toMemory: ())
var urlInput:NSURL?
convenience init(srcURL:NSURL, targetURL:NSURL) {
self.init()
self.fileInput = NSInputStream(URL: srcURL)
self.copyOutput = NSOutputStream(URL: targetURL, append: false)
self.urlInput = srcURL
}
func copyFileURLToURL(destURL:NSURL, withProgressBlock block: (fileSize:Double,percent:Double,estimatedTimeRemaining:Double) -> ()){
guard let copyOutput = self.copyOutput, let fileInput = self.fileInput, let urlInput = self.urlInput else { return }
let fileSize = sizeOfInputFile(urlInput)
let bufferSize = 4096
let buffer = UnsafeMutablePointer<UInt8>.alloc(bufferSize)
//var buffer:UnsafeMutablePointer<UInt16> = UnsafeMutablePointer(malloc(Int(bufferSize)))
var bytesToWrite = 0
var bytesWritten = 0
var counter = 0
var copySize = 0
fileInput.open()
copyOutput.open()
//start time
let time0 = mach_absolute_time()
while fileInput.hasBytesAvailable {
repeat {
bytesToWrite = fileInput.read(buffer, maxLength: bufferSize)
bytesWritten = copyOutput.write(buffer, maxLength: bufferSize)
//check for errors
if bytesToWrite < 0 {
print(fileInput.streamStatus.rawValue)
}
if bytesWritten == -1 {
print(copyOutput.streamStatus.rawValue)
}
//move read pointer to next section
bytesToWrite -= bytesWritten
copySize += bytesWritten
if bytesToWrite > 0 {
//move block of memory
memmove(buffer, buffer + bytesWritten, bytesToWrite)
}
} while bytesToWrite > 0
if fileSize != nil && (++counter % 10 == 0) {
//passback a progress tuple
let percent = Double(copySize/fileSize!)
let time1 = mach_absolute_time()
let elapsed = Double (time1 - time0)/Double(NSEC_PER_SEC)
let estTimeLeft = ((1 - percent) / percent) * elapsed
block(fileSize: Double(copySize), percent: percent, estimatedTimeRemaining: estTimeLeft)
}
}
//send final progress tuple
block(fileSize: Double(copySize), percent: 1, estimatedTimeRemaining: 0)
//close streams
if fileInput.streamStatus == .AtEnd {
fileInput.close()
}
if copyOutput.streamStatus != .Writing && copyOutput.streamStatus != .Error {
copyOutput.close()
}
}
func sizeOfInputFile(src:NSURL) -> Int? {
do {
let fileSize = try NSFileManager.defaultManager().attributesOfItemAtPath(src.path!)
return fileSize["fileSize"] as? Int
} catch let inputFileError as NSError {
print(inputFileError.localizedDescription,inputFileError.localizedRecoverySuggestion)
}
return nil
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment