반응형
카테고리 | 게시글 작성 날짜 | 게시글 최근 수정 날짜 | 작성자 |
Operating System | 2022.02.08. 22:30 | 2022.02.14. 20:57 | Dev.Yang |
아래의 첨부 파일은 Minizip OpenSource Library 입니다.
아래의 첨부 파일은 전체적인 프로젝트 파일입니다.
압축 (Compression) 속성은 NoCompression (압축을 하지 않음), BestSpeed (압축률 가장 낮지만 시간 빠름), DefaultCompression (기본적인 압축률), BestCompression (압축률이 가장 높지만 시간 느림)이 있습니다.
구현 된 소스코드 (Source Code)는 아래의 예시처럼 사용할 수 있습니다.
let target = URL(fileURLWithPath: "")
let zipFilePath = URL(fileURLWithPath: "")
macMiniZip.shared.compressZip(paths: [target],
zipFilePath: zipFilePath,
password: "password",
compression: .DefaultCompression) { progress, isEnd in }
🛠 macOS MiniZip with Swift Source Code
더보기
/*
* Copyright (c) 2022 ChangYeop-Yang All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
import Minizip
import Foundation
/**
- Date: `2022.02.08. 22:38:24`
- Version: `[Lasted] 1.0.0.0`
- NOTE: [Zip](https://github.com/marmelroy/Zip) 오픈소스 기반으로 구현되었습니다.
- Authors: `ChangYeop-Yang`
- Copyright: `Copyright (c) 2022 양창엽. All rights reserved.`
*/
public class macMiniZip: NSObject {
// MARK: - Enum
public enum ZipCompression: Int {
case NoCompression
case BestSpeed
case DefaultCompression
case BestCompression
// MARK: Enum Properties
internal var minizipCompression: Int32 {
switch self {
case .NoCompression:
return Z_NO_COMPRESSION
case .BestSpeed:
return Z_BEST_SPEED
case .DefaultCompression:
return Z_DEFAULT_COMPRESSION
case .BestCompression:
return Z_BEST_COMPRESSION
}
}
}
// MARK: - Strucut
fileprivate struct ProcessedFilePath {
fileprivate let filePathURL: URL
fileprivate let fileName: String?
// MARK: Strucut Method
fileprivate func filePath() -> String { return filePathURL.path }
}
// MARK: - Object Properteis
internal static let shared = macMiniZip()
private let chunkSize: Int = 16384
private let includeRootDirectory: Bool = true
// MARK: - Initalize
private override init() { super.init() }
}
// MARK: - Private Extension Zip
private extension macMiniZip {
func getAttributesOfItem(filePath: String) -> [FileAttributeKey : Any]? {
do {
return try FileManager.default.attributesOfItem(atPath: filePath)
} catch let error as NSError {
assert(false, error.localizedDescription)
return nil
}
}
func getFileSize(filePath: String) -> Double {
guard let attribute = getAttributesOfItem(filePath: filePath) else { return Double.zero }
guard let fileSize = attribute[FileAttributeKey.size] as? Double else { return Double.zero }
return fileSize
}
func createZipFileInfo(filePath: String) -> zip_fileinfo? {
let defaultDate = tm_zip(tm_sec: 0, tm_min: 0, tm_hour: 0, tm_mday: 0, tm_mon: 0, tm_year: 0)
var zipInfo = zip_fileinfo(tmz_date: defaultDate, dosDate: 0, internal_fa: 0, external_fa: 0)
guard let attribute = getAttributesOfItem(filePath: filePath) else { return nil }
guard let fileDate = attribute[FileAttributeKey.modificationDate] as? Date else { return nil }
let components = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute, .second], from: fileDate)
zipInfo.tmz_date.tm_sec = UInt32(components.second ?? Int.zero)
zipInfo.tmz_date.tm_min = UInt32(components.minute ?? Int.zero)
zipInfo.tmz_date.tm_hour = UInt32(components.hour ?? Int.zero)
zipInfo.tmz_date.tm_mday = UInt32(components.day ?? Int.zero)
zipInfo.tmz_date.tm_mon = UInt32(components.month ?? Int.zero)
zipInfo.tmz_date.tm_year = UInt32(components.year ?? Int.zero)
return zipInfo
}
func processZipPaths(_ paths: [URL]) -> [ProcessedFilePath]{
var processedFilePaths = [ProcessedFilePath]()
for path in paths {
let filePath = path.path
var isDirectory: ObjCBool = false
_ = FileManager.default.fileExists(atPath: filePath, isDirectory: &isDirectory)
if !isDirectory.boolValue {
let processedPath = ProcessedFilePath(filePathURL: path, fileName: path.lastPathComponent)
processedFilePaths.append(processedPath)
}
else {
let directoryContents = expandDirectoryFilePath(path)
processedFilePaths.append(contentsOf: directoryContents)
}
}
return processedFilePaths
}
func expandDirectoryFilePath(_ directory: URL) -> [ProcessedFilePath] {
var processedFilePaths = [ProcessedFilePath]()
let directoryPath = directory.path
if let enumerator = FileManager.default.enumerator(atPath: directoryPath) {
while let filePathComponent = enumerator.nextObject() as? String {
let path = directory.appendingPathComponent(filePathComponent)
let filePath = path.path
var isDirectory: ObjCBool = false
_ = FileManager.default.fileExists(atPath: filePath, isDirectory: &isDirectory)
if !isDirectory.boolValue {
var fileName = filePathComponent
if includeRootDirectory {
let directoryName = directory.lastPathComponent
fileName = (directoryName as NSString).appendingPathComponent(filePathComponent)
}
let processedPath = ProcessedFilePath(filePathURL: path, fileName: fileName)
processedFilePaths.append(processedPath)
}
}
}
return processedFilePaths
}
}
// MARK: - Puiblic Extension Zip
public extension macMiniZip {
func compressZip(paths: [URL], zipFilePath: URL, password: String,
compression: ZipCompression, progress: (Double, Bool) -> Swift.Void) {
// Check whether a zip file exists at path.
let destinationPath = zipFilePath.path
// Process zip paths
let processedPaths = self.processZipPaths(paths)
// Progress handler set up
var totalSize = Double.zero
var currentPosition = Double.zero
// Get totalSize for progress handler
processedPaths.forEach { [unowned self] path in
let filePath = path.filePath()
totalSize = totalSize + self.getFileSize(filePath: filePath)
}
let progressTracker = Progress(totalUnitCount: Int64(totalSize))
progressTracker.isCancellable = false
progressTracker.isPausable = false
progressTracker.kind = ProgressKind.file
let zip = zipOpen(destinationPath, APPEND_STATUS_CREATE)
for path in processedPaths {
let filePath = path.filePath()
var isDirectory: ObjCBool = false
// 압축하고자 하는 대상이 파일이 존재하지 않는 경우에는 압축 작업을 수행하지 않습니다.
guard FileManager.default.fileExists(atPath: filePath, isDirectory: &isDirectory) else { continue }
// 압축하고자 하는 대상이 파일이 아닌 폴더인 경우에는 작업을 수행하지 않습니다.
if !isDirectory.boolValue {
// 압축하고자 하는 대상에 대한 파일 내용을 읽어들이기 위해서 파일을 열지 못하는 경우에는 압축 작업을 수행하지 않습니다.
guard let input = fopen(filePath, "r") else { continue }
// 압축하고자 하는 대상에 대한 파일 이름을 가져오지 못하는 경우에는 압축 작업을 수행하지 않습니다.
guard let fileName = path.fileName else {
fclose(input)
continue
}
// 압축하고자 하는 대상에 대한 파일 정보를 가져오지 못하는 경우에는 압축 작업을 수행하지 않습니다.
guard var zipInfo = createZipFileInfo(filePath: filePath) else {
fclose(input)
continue
}
currentPosition += getFileSize(filePath: filePath)
zipOpenNewFileInZip3(zip, fileName, &zipInfo, nil, 0, nil, 0, nil,
Z_DEFLATED, compression.minizipCompression, 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
password, 0)
let buffer = malloc(self.chunkSize)
while feof(input) == Int32.zero {
let length = fread(buffer, 1, chunkSize, input)
zipWriteInFileInZip(zip, buffer, UInt32(length))
}
// 현재 압축 작업 중인 파일 크기와 전체 압축 파일 크기를 나누어 작업 중인 크기를 전달합니다.
progress(currentPosition/totalSize, false)
progressTracker.completedUnitCount = Int64(currentPosition)
zipCloseFileInZip(zip)
free(buffer)
fclose(input)
}
}
zipClose(zip, nil)
// Completed. Update progress handler.
progress(Double.nan, true)
progressTracker.completedUnitCount = Int64(totalSize)
}
}
🚀 REFERENCE
반응형
'# 사용하지 않는 게시글' 카테고리의 다른 글
[OS - 🍎 macOS] Cocoa CustomView 가져오는 방법 (Working with Custom Views) (0) | 2022.12.14 |
---|---|
[iOS] Thread Safety Array in Swift (0) | 2022.07.20 |
댓글