Last active
August 2, 2021 16:13
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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