@@ -10,27 +10,28 @@ import CryptoKit
1010
1111typealias Operation = ( Data ) throws -> Data
1212typealias FinalOperation = ( ) throws -> Data
13- typealias StreamsBlock = ( InputStream , OutputStream ) async throws -> ( )
13+ typealias SafeStreamBlock = ( OutputStream ) async throws -> ( )
1414
1515@available ( macOS 12 . 0 , iOS 15 . 0 , * )
1616func process( file src: URL , to dest: URL , using key: SymmetricKey , bufferSize: Int = 32 * 1000 ,
1717 operation: Operation , finalOperation: FinalOperation ? = nil ,
1818 onProgress: OnProgress ? ) async throws {
19- try await stream ( from: src, to: dest) { input, output in
20-
21- guard let fileSize = src. fileSize else {
22- throw ProccessingError . fileNotFound
23- }
24-
19+ guard let fileSize = src. fileSize else {
20+ throw ProccessingError . fileNotFound
21+ }
22+
23+ try await safeStream ( to: dest) { output in
2524 var offset : Int = 0
2625 var count = 0
2726
28- try await input. readAll ( bufferSize: bufferSize) { buffer, bytesRead in
29- offset += bytesRead
27+ let batches = src. resourceBytes. chunked ( countOf: bufferSize)
28+ for try await batch in batches {
29+ offset += batch. count
3030 onProgress ? ( Int ( ( offset * 100 ) / fileSize) )
3131
32- let data = Data ( bytes: buffer, count: bytesRead)
33- output. write ( data: try operation ( data) )
32+ let processedData = try operation ( Data ( batch) )
33+ output. write ( data: processedData)
34+
3435 count = ( count + 1 ) % 10
3536 if count == 0 {
3637 await Task . yield ( )
@@ -44,24 +45,21 @@ func process(file src: URL, to dest: URL, using key: SymmetricKey, bufferSize: I
4445}
4546
4647@available ( macOS 12 . 0 , iOS 15 . 0 , * )
47- private func stream ( from src : URL , to dest: URL , operation: StreamsBlock ) async throws {
48+ private func safeStream ( to dest: URL , operation: SafeStreamBlock ) async throws {
4849 let fm = FileManager . default
4950
5051 let tempDir = fm. temporaryDirectory
5152 try fm. createDirectory ( at: tempDir, withIntermediateDirectories: true , attributes: nil )
5253 let tempFile = tempDir. appendingPathComponent ( UUID ( ) . uuidString)
5354
54- guard let input = InputStream ( url: src) else {
55- throw ProccessingError . failedToCreateInputStream
56- }
5755 guard let output = OutputStream ( url: tempFile, append: false ) else {
5856 throw ProccessingError . failedToCreateOutputStream
5957 }
6058
6159 output. open ( )
6260 defer { output. close ( ) }
6361
64- try await operation ( input , output)
62+ try await operation ( output)
6563
6664 if fm. fileExists ( atPath: dest. path) {
6765 try fm. removeItem ( at: dest)
@@ -78,24 +76,6 @@ extension URL {
7876 }
7977}
8078
81- extension InputStream {
82- typealias Buffer = [ UInt8 ]
83-
84- @available ( macOS 12 . 0 , iOS 15 . 0 , * )
85- func readAll( bufferSize: Int , block: ( Buffer , Int ) async throws -> Void ) async rethrows {
86- open ( )
87- defer { close ( ) }
88-
89- var buffer = [ UInt8] ( repeating: 0 , count: bufferSize)
90- while hasBytesAvailable {
91- let bytesRead = read ( & buffer, maxLength: buffer. count)
92- guard bytesRead > 0 else { break }
93-
94- try await block ( buffer, bytesRead)
95- }
96- }
97- }
98-
9979extension OutputStream {
10080 func write( data: Data ) {
10181 let buffer = [ UInt8] ( data)
@@ -105,13 +85,11 @@ extension OutputStream {
10585
10686enum ProccessingError : LocalizedError {
10787 case fileNotFound
108- case failedToCreateInputStream
10988 case failedToCreateOutputStream
11089
11190 var errorDescription : String ? {
11291 switch self {
11392 case . fileNotFound: return " Source file not found "
114- case . failedToCreateInputStream: return " Failed to create input stream from source file "
11593 case . failedToCreateOutputStream: return " Failed to create output stream to destination file "
11694 }
11795 }
0 commit comments