avatar
童琦杰
Oct 27, 2022Technology

Swift - 文件相关操作

系统目录

缓存目录、下载目录、文档目录

swift
public static var cachesDirectory: URL? {
    get {
        return FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first
    }
}

public static var downloadsDirectory: URL? {
    get {
        return FileManager.default.urls(for: .downloadsDirectory, in: .userDomainMask).first
    }
}

public static var documentDirectory: URL? {
    get {
        return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
    }
}

获取文件/目录大小

swift
public static func sizeOf(file: URL) -> Int? {
    if !File.exists(file: file) {
        return nil
    }
    do {
        let attributes = try FileManager.default.attributesOfItem(atPath: file.path)
        if let size = attributes[.size] as? Int {
            return size
        }
        print("failde to calculate size of file \(file.path)")
        return nil
    } catch {
        print("failed to calculate size of file \(file.path)\n\(error)")
        return nil
    }
}

public static func sizeOf(directory: URL) -> Int? {
    var totalSize = 0
    do {
        let contents = try FileManager.default.contentsOfDirectory(atPath: directory.path)
        for content in contents {
            let contentURL = directory.appendingPathComponent(content)
            let attributes = try FileManager.default.attributesOfItem(atPath: contentURL.path)
            guard let type = attributes[.type] as? String else {
                continue
            }
            if type == "NSFileTypeDirectory",
               let size = sizeOf(directory: contentURL) {
                totalSize += size
                continue
            }
            if let size = attributes[.size] as? Int {
                totalSize += size
                continue
            }
            print("failde to calculate size of item \(contentURL.path)")
            return nil
        }
    } catch {
        print("failed to calculate size of folder \(directory.path)\n\(error)")
        return nil
    }
    return totalSize
}

获取指定目录下文件/目录

swift
public static func entitiesOf(directory: URL) -> [Entity] {
    if !File.exists(directory: directory) {
        return []
    }
    var entities = [Entity]()
    do {
        let contents = try FileManager.default.contentsOfDirectory(atPath: directory.path)
        for content in contents {
            let contentURL = directory.appendingPathComponent(content)
            let attributes = try FileManager.default.attributesOfItem(atPath: contentURL.path)
            guard let type = attributes[.type] as? String else {
                continue
            }
            if type == "NSFileTypeDirectory" {
                entities.append(Entity(url: contentURL, type: .directory))
            } else {
                entities.append(Entity(url: contentURL, type: .file))
            }
        }
    } catch {
        print("failed to calculate size of folder \(directory.path)\n\(error)")
        return []
    }
    return entities
}

public struct Entity {
    let url: URL
    let type: EntityType
    public init(url: URL, type: EntityType) {
        self.url = url
        self.type = type
    }
}

public enum EntityType {
    case file
    case directory
}

检查文件/目录是否存在

swift
public static func exists(file: URL) -> Bool {
    var isDirectory : ObjCBool = false
    return FileManager.default.fileExists(atPath: file.path, isDirectory: &isDirectory) && !isDirectory.boolValue
}

public static func exists(directory: URL) -> Bool {
    var isDirectory : ObjCBool = false
    return FileManager.default.fileExists(atPath: directory.path, isDirectory: &isDirectory) && isDirectory.boolValue
}

创建文件/目录

如果已经存在则不会覆盖创建

swift
@discardableResult
public static func create(file: URL, length: Int) -> Bool {
    if File.exists(file: file) {
        return false
    }
    return FileManager.default.createFile(atPath: file.path, contents: Data(count: length), attributes: nil)
}

@discardableResult
public static func create(directory: URL) -> Bool {
    if File.exists(directory: directory) {
        return false
    }
    do {
        try FileManager.default.createDirectory(atPath: directory.path, withIntermediateDirectories: true, attributes: nil)
        return true
    } catch {
        print("failed to create folder: \(directory.path)\n\(error)")
        return false
    }
}

删除文件/目录

swift
@discardableResult
public static func delete(at: URL) -> Bool {
    do {
        try FileManager.default.removeItem(at: at)
        return true
    } catch {
        print("failed to remove file \(at.path)\n\(error)")
        return false
    }
}

移动文件/目录

swift
@discardableResult
public static func move(at: URL, to: URL) -> Bool {
    do {
        try FileManager.default.moveItem(at: at, to: to)
        return true
    } catch {
        print("failed to move file from \(at.path) to \(to.path)\n\(error)")
        return false
    }
}

写入文件

swift
@discardableResult
public static func write(to: URL, string: String) -> Bool {
    do {
        try string.write(to: to, atomically: true, encoding: .utf8)
        return true
    } catch {
        print("failed to write string to \(to.absoluteString)\n\(error)")
        return false
    }
}

@discardableResult
public static func write(to: URL, data: Data, offset: Int) -> Bool {
    if !File.exists(file: to) && !File.create(file: to, length: 0) {
        print("failde to write data to \(to.path) because file fails to create")
    }
    guard let fileHandle = FileHandle(forWritingAtPath: to.path) else {
        print("failde to write data to \(to.path) because file handle fails to create")
        return false
    }
    do {
        try fileHandle.seek(toOffset: UInt64(offset))
        fileHandle.write(data)
        try fileHandle.close()
        return true
    } catch {
        print("failde to write data to \(to.path)\n\(error)")
        return false
    }
}

读取文件

swift
public static func readString(from: URL) -> String? {
    if !File.exists(file: from) {
        print("failde to read string from \(from.path) because file does not exist")
        return nil
    }
    do {
        return try String(contentsOfFile: from.path)
    } catch {
        print("failde to read string from \(from.path)\n\(error)")
        return nil
    }
}

public static func readData(from: URL) -> Data? {
    if !File.exists(file: from) {
        print("failde to read data from \(from.path) because file does not exist")
        return nil
    }
    do {
        return try Data(contentsOf: from)
    } catch {
        print("failde to read data from \(from.path)\n\(error)")
        return nil
    }
}

public static func readData(from: URL, offset: Int, length: Int) -> Data? {
    if !File.exists(file: from) {
        print("failde to read data from \(from.path) because file does not exist")
        return nil
    }
    guard let fileHandle = FileHandle(forReadingAtPath: from.path) else {
        print("failde to read data from \(from.path) because file handle fails to create")
        return nil
    }
    do {
        try fileHandle.seek(toOffset: UInt64(offset))
        let data = fileHandle.readData(ofLength: length)
        try fileHandle.close()
        return data
    } catch {
        print("failde to read data from \(from.path)\n\(error)")
        return nil
    }
}
© 2015-2022 tongqijie.com 版权所有沪ICP备17000682号