Simple and expressive file management in Swift

Related tags

swift files paths
Overview

FileKit is a Swift framework that allows for simple and expressive file management.

Development happens in the develop branch.

Installation

Compatibility

  • OS X 10.9+ / iOS 8.0+ / watchOS 2.0 / tvOS 9.0

  • Xcode 7.1+, Swift 2.1+

Install Using CocoaPods

CocoaPods is a centralized dependency manager for Objective-C and Swift. Go here to learn more.

  1. Add the project to your Podfile.

    use_frameworks!
    
    pod 'FileKit', '~> 5.0.0'
  2. Run pod install and open the .xcworkspace file to launch Xcode.

  3. Import the FileKit framework.

    import FileKit

Install Using Carthage

Carthage is a decentralized dependency manager for Objective-C and Swift.

  1. Add the project to your Cartfile.

    github "nvzqz/FileKit"
    
  2. Run carthage update and follow the additional steps in order to add FileKit to your project.

  3. Import the FileKit framework.

    import FileKit

Usage

Paths

Paths are handled with the Path structure.

let home = Path("~")
let drive: Path = "/Volumes/Macintosh HD"
let file:  Path = "~/Desktop/file\(1)"

Operations

New Files

A blank file can be written by calling createFile() on an Path.

try Path(".gitignore").createFile()
New Directories

A directory can be created by calling createDirectory() on an Path.

try Path("~/Files").createDirectory()
try Path("~/Books").createDirectory(withIntermediateDirectories: false)

Intermediate directories are created by default.

New Symlinks

A symbolic link can be created by calling createSymlinkToPath(_:) on an Path.

try Path("path/to/MyApp.app").symlinkFile(to: "~/Applications")
print(Path("~/Applications/MyApp.app").exists)  // true
Finding Paths

You can find all paths with the ".txt" extension five folders deep into the Desktop with:

let textFiles = Path.userDesktop.find(searchDepth: 5) { path in
    path.pathExtension == "txt"
}

A negative searchDepth will make it run until every path in self is checked against.

You can even map a function to paths found and get the non-nil results:

let documents = Path.userDocuments.find(searchDepth: 1) { path in
    String(path)
}
Iterating Through Paths

Because Path conforms to SequenceType, it can be iterated through with a for loop.

for download in Path.userDownloads {
    print("Downloaded file: \(download)")
}
Current Working Directory

The current working directory for the process can be changed with Path.Current.

To quickly change the current working directory to a path and back, there's the changeDirectory(_:) method:

Path.userDesktop.changeDirectory {
    print(Path.current)  // "/Users/nvzqz/Desktop"
}
Common Ancestor

A common ancestor between two paths can be obtained:

print(Path.root.commonAncestor(.userHome))       // "/"
print("~/Desktop"  <^> "~/Downloads")            // "~"
print(.UserLibrary <^> .UserApplicationSupport)  // "/Users/nvzqz/Library"
+ Operator

Appends two paths and returns the result

// ~/Documents/My Essay.docx
let essay = Path.userDocuments + "My Essay.docx"

It can also be used to concatenate a string and a path, making the string value a Path beforehand.

let numberedFile: Path = "path/to/dir" + String(10)  // "path/to/dir/10"
+= Operator

Appends the right path to the left path. Also works with a String.

var photos = Path.userPictures + "My Photos"  // ~/Pictures/My Photos
photos += "../My Other Photos"                // ~/Pictures/My Photos/../My Other Photos
% Operator

Returns the standardized version of the path.

let path: Path = "~/Desktop"
path% == path.standardized  // true
* Operator

Returns the resolved version of the path.

let path: Path = "~/Documents"
path* == path.resolved  // true
^ Operator

Returns the path's parent path.

let path: Path = "~/Movies"
path^ == "~"  // true
->> Operator

Moves the file at the left path to the right path.

Path counterpart: moveFile(to:)

File counterpart: move(to:)

->! Operator

Forcibly moves the file at the left path to the right path by deleting anything at the left path before moving the file.

+>> Operator

Copies the file at the left path to the right path.

Path counterpart: copyFile(to:)

File counterpart: copy(to:)

+>! Operator

Forcibly copies the file at the left path to the right path by deleting anything at the left path before copying the file.

=>> Operator

Creates a symlink of the left path at the right path.

Path counterpart: symlinkFile(to:)

File counterpart: symlink(to:)

=>! Operator

Forcibly creates a symlink of the left path at the right path by deleting anything at the left path before creating the symlink.

Subscripting

Subscripting an Path will return all of its components up to and including the index.

let users = Path("/Users/me/Desktop")[1]  // /Users
standardize()

Standardizes the path.

The same as doing:

somePath = somePath.standardized
resolve()

Resolves the path's symlinks.

The same as doing:

somePath = somePath.resolved

Files

A file can be made using File with a DataType for its data type.

let plistFile = File<Dictionary>(path: Path.userDesktop + "sample.plist")

Files can be compared by size.

Operators

|> Operator

Writes the data on the left to the file on the right.

do {
    try "My name is Bob." |> TextFile(path: Path.userDesktop + "name.txt")
} catch {
    print("I can't write to a desktop file?!")
}

TextFile

The TextFile class allows for reading and writing strings to a file.

Although it is a subclass of File<String>, TextFile offers some functionality that File<String> doesn't.

|>> Operator

Appends the string on the left to the TextFile on the right.

let readme = TextFile(path: "README.txt")
try "My Awesome Project" |> readme
try "This is an awesome project." |>> readme

NSDictionaryFile

A typealias to File<NSDictionary>.

NSArrayFile

A typealias to File<NSArray>

NSDataFile

A typealias to File<NSData>

DataFile

The DataFile class allows for reading and writing Data to a file.

Although it is a subclass of File<Data>, DataFile offers some functionality that File<Data> doesn't. You could specify Data.ReadingOptions and Data.WritingOptions

Encodable/Decodable

You can use any Codable object with File.

extension AnyCodableClass: JSONReadableWritable {} // if you want json encoding/decoding

let codableFile = File<AnyCodableClass>(path: path)
try codableFile.write(toEncode)
let decoded: AnyCodableClass = try codableFile.read()

Alternatively you can use utility methods

try FileKit.write(toEncode, to: path)
let decoded: AnyCodableClass = try FileKit.read(from: path)

File Permissions

The FilePermissions struct allows for seeing the permissions of the current process for a given file.

let swift: Path = "/usr/bin/swift"
print(swift.filePermissions)  // FilePermissions[read, execute]

Data Types

All types that conform to DataType can be used to satisfy the generic type for File.

Readable Protocol

A Readable type must implement the static method read(from: Path).

All Readable types can be initialized with init(contentsOfPath:).

Writable Protocol

A Writable type must implement write(to: Path, atomically: Bool).

Writing done by write(to: Path) is done atomically by default.

WritableToFile

Types that have a write(toFile:atomically:) method that takes in a String for the file path can conform to Writable by simply conforming to WritableToFile.

WritableConvertible

If a type itself cannot be written to a file but can output a writable type, then it can conform to WritableConvertible and become a Writable that way.

FileKitError

The type for all errors thrown by FileKit operations is FileKitError.

Errors can be converted to String directly for any logging. If only the error message is needed, FileKitError has a message property that states why the error occurred.

// FileKitError(Could not copy file from "path/to/file" to "path/to/destination")
String(FileKitError.copyFileFail(from: "path/to/file", to: "path/to/destination"))

License

FileKit and its assets are released under the MIT License. Assets can be found in the assets branch.

Issues
  • Clean up API and add Swift 3 support

    Clean up API and add Swift 3 support

    Future API should be written to be compatible with Swift 3.

    Because Swift 2 support is being dropped, this is a breaking change that will result in a major version change for FileKit to 4.0.0.

    Also, a lot of documentation is also either ambiguous or just weirdly worded.

    Cleaning up the API entails following the Swift API Style Guidelines.

    Note: Adding Swift 3 support consists of keeping this up to date with Swift 3 until a final release is made. Then there'll be no breaking changes, allowing for version 4.

    • [x] Swift 3 compatibility #27
    • [x] Cleaned up API
    enhancement 
    opened by nvzqz 24
  • Support Swift 4

    Support Swift 4

    When do you plan to add support for Swift 4

    help wanted 
    opened by Vitaliyy-jomedia 10
  • save file from Alamofire

    save file from Alamofire

    I am getting a file base64 string from alamofire . how to save as a file

    help wanted 
    opened by subinkk08 10
  • tvOS target broken – doesn't build

    tvOS target broken – doesn't build

    See the image below: ohne titel

    OSX, iOS and watchOS targets are working correctly. Using XCode 7.2.

    bug 
    opened by Jeehut 6
  • Please update cocoapods version to 6.0.0

    Please update cocoapods version to 6.0.0

    The latest version on cocoapods is 5.2.0, please update to 6.0.0, Thanks!

    image

    opened by luoxiu 5
  • Fix bug + Add FS Event for iOS

    Fix bug + Add FS Event for iOS

    Add GCD based FS Event. Support for iOS Fix bug: crash when NSFileManager delegate deinit. Fix bug: commonAncestor Fix bug: miss self in FileKit/Core/File.swift Using _rawValue in API calls to avoid empty string which may cause crash. Using isAny to detect any type of file exists at path. Using stdWithTilde to standardize the path without expanding tilde. Better support for relative path. Like Path("./../dir1/../dir2/file/.//").parent is Path("../../dir2/file") Annotations for follow links or not. Support for expanding tilde.

    opened by ijumps 5
  • How to read and write line by line?

    How to read and write line by line?

    Why is it that there are no file read and write routines to read individual lines from a file, or write individual lines to a file, without having to open and close the file around each line (such as your |>> operator)?

    I really love the Swift language, except that I can't read or write a text file in a normal manner. Reading the whole file at once is great... unless your file is several Megabytes, or several Terabytes long. I really just want to read a file, line by line, in a way that won't eat up all of memory.

    I'm just frustrated, saw your library, and thought that it might be the solution I was looking for. O.o

    question 
    opened by rpural 5
  • Cannot call value of non-function type 'FileType?'

    Cannot call value of non-function type 'FileType?'

    Hi, I'm getting a compiler error when building my macOS app using FileKit integrated with Cocoapods.

    The app is for macOS 10.13. I'm using Xcode 9.0.1, Cocoapods and FileKit 4.0.1 (5.0.0 was not available over Cocoapods)

    If I want to compile the I getting this error:

    Cannot call value of non-function type 'FileType?' in

    extension File: CustomStringConvertible {
    
        // MARK: - CustomStringConvertible
    
        /// A textual representation of `self`.
        public var description: String {
            return String(describing: type(of: self)) + "('" + path.description + "')"
        }
    
    }
    
    opened by RabbitMC 5
  •  Cannot convert value of type '[FileAttributeKey : Any]' to expected argument type '[String : Any]?'

    Cannot convert value of type '[FileAttributeKey : Any]' to expected argument type '[String : Any]?'

    Xcode9 after pod install Swift Compiler Error Group: /Users/matthewxu/project/LiLiTools/Pods/FileKit/Sources/FileProtection.swift:126:82: Cannot convert value of type '[FileAttributeKey : Any]' to expected argument type '[String : Any]?' on manager.createFile(atPath: _safeRawValue, contents: nil, attributes: attributes) { in the following codes

    public func createFile(_ fileProtection: FileProtection) throws {
           let manager = FileManager()
           let attributes: [FileAttributeKey : Any] = [.protectionKey: fileProtection] // todo test
    
           if !manager.createFile(atPath: _safeRawValue, contents: nil, attributes: attributes) { 
               throw FileKitError.createFileFail(path: self)
           }
       }
    

    Any one meet this issue and how to solve it

    opened by matthewxu 5
  • How to use the `Path` class while already having a class named `Path`?

    How to use the `Path` class while already having a class named `Path`?

    I tried FileKit.Path with no gain.

    opened by ahmedk92 5
  • CocoaPods extremely out-of-date (5.2 when it should be 6.0)

    CocoaPods extremely out-of-date (5.2 when it should be 6.0)

    I was able to find this issue https://github.com/nvzqz/FileKit/issues/73 but I do not understand why it was closed without any resolution. Does no-one maintaining this project have access to update the Podspec in the public CocoaPods repo? I am happy to help in anyway I can to make this happen. Thanks!

    opened by tony-osibov 0
  • Typo in ReadMe?

    Typo in ReadMe?

    +>! Operator
    
    Forcibly copies the file at the left path to the right path by deleting anything at the left path before copying the file.
    

    Should that be "Forcibly copies the file at the left path to the right path by deleting anything at the RIGHT path before copying the file." ? If not, wouldn't it be a move instead of a copy?

    opened by transat 0
  • Deprecated method FileHandle.write(Data)

    Deprecated method FileHandle.write(Data)

    https://github.com/nvzqz/FileKit/blob/38fb74327387b1c8accd257177ef4c4cc00c1fbb/Sources/TextFile.swift#L299

    The method may crash an app. Can you replace with a safe method?

    opened by alex-dubatov 0
  • Is there a way to write files to icloud using file kit?

    Is there a way to write files to icloud using file kit?

    If yes then what the path that should be used and what changes are required for xcode project to support icloud on macOS

    enhancement 
    opened by IgorMuzyka 2
  • Path + String produces bad AnySequence result if Path ends with / and String starts with /

    Path + String produces bad AnySequence result if Path ends with / and String starts with /

    When adding a String to a Path, if the Path ends with / and the String starts with / then the results include AnySequence garbage.

    import FileKit
    
    print(Path("/Foo/bar/") + "/wat")
    // prints:
    // /Foo/bar/AnySequence<Path>(_box: Swift._SequenceBox<Swift._DropFirstSequence<FileKit.DirectoryEnumerator>>)
    

    Tested with the latest develop (7521741d10b9e4c9b3eb1501191652f821eb3142) on Swift 4.1.2.

    bug 
    opened by lilyball 0
  • Feature Request: For adding/removing extended file attributes

    Feature Request: For adding/removing extended file attributes

    It would be great to have a way to add/remove extended file attributes. For example, If I wanted to associate different display name for file rather than original name of file. In such case, extended file attributes can come in handy.

    enhancement 
    opened by RPethani 1
  • warning: 'ExpressibleByStringInterpolation' is deprecated

    warning: 'ExpressibleByStringInterpolation' is deprecated

    Hi, When I build your component with carthage I have these warnings:

    ../Sources/Carthage/Checkouts/FileKit/Sources/Path.swift:1066:17: warning: 'ExpressibleByStringInterpolation' is deprecated: it will be replaced or redesigned in Swift 4.0.  Instead of conforming to 'ExpressibleByStringInterpolation', consider adding an 'init(_:String)'
    ../Sources/Carthage/Checkouts/FileKit/Sources/TextFile.swift:231:21: warning: conditional downcast from 'NSString?' to 'String' is a bridging conversion; did you mean to use 'as'?
    
    help wanted 
    opened by TofPlay 5
  • Issues building on Linux with swift 3.0.1

    Issues building on Linux with swift 3.0.1

    I just tried building this on an linux machine running Ubuntu 16.04 with swift 3.0.1 and there were several build errors.

    failures.txt

    I will attempt running this on my macOS laptop to see if I get the same failures

    opened by Ponyboy47 13
  • How to get relative path?

    How to get relative path?

    It's have a easy method to get relative path?

    enhancement 
    opened by devSC 3
  • testWatch() Fails on First Run

    testWatch() Fails on First Run

    When testing FileKit, testWatch() will sometimes fail on the first attempt. I'm not familiar with GCD, so I don't necessarily know why this occurs.

    opened by nvzqz 3
Releases(5.3.0)
  • 5.3.0(Sep 1, 2019)

  • 6.0.0(Sep 1, 2019)

  • v5.2.0(Sep 18, 2018)

  • v5.1.0(Sep 17, 2018)

  • v5.0.0(Sep 17, 2018)

  • v4.0.0(Oct 5, 2016)

  • v3.0.0(Jul 20, 2016)

    Release Notes

    This release is mainly to make all current features available.

    New Features

    • File system watching
    • Added workingDirectory to Process
    • Added createFile(_:) create(_:) methods to Path and File
    • Added reading and writing for File with NSData type
    • Added grep operations for TextFile
    • Added init(groupIdentifier:) to Path
    • Added additional static paths
    • Added / operator for appending paths
    • Hard linking files

    Changes

    • Renamed AllArray and AllNames in FileSystemEventFlags to allFlags and allFlagNames.
    • Changed returned description and debug description strings for FileSystemEventFlags
      • Now contains the name of the type
    • FileSystemEventStream is now private
    • Removed global NSFileManager for Path
      • Each Path instance now has a fileManagerDelegate
    • Expanded name abbreviations
      • "CGD" -> "Dispatch"

    Fixes

    • readFromPath for NSData now actually returns the contents
    • Fixed commonAncestor(_:) method for Path
    Source code(tar.gz)
    Source code(zip)
  • v2.0.0(Nov 24, 2015)

    Release Notes

    Important:

    • The 'FK' prefix for FileKit types has been removed in an effort to make the library less cumbersome and more "Swifty" to use. :large_orange_diamond:
    • FileType is no longer a protocol for files. It is now an enumeration of types that a given file can be. The File class is now the standard form of interacting with files.

    New Features

    • FileKit enumeration to get info regarding the current version of FileKit

    • tvOS support :tv:

    • DirectoryEnumerator struct to enumerate through the files in a directory.

    • Settable path extension

    • A path's children can now be obtained recursively

      let allFilesInHome = Path.UserHome.children(recursive: true)
      
    • String and Path concatenation with the + operator

    • A changeDirectory(_:) to Path that changes the process' current working directory to self

      Path.UserDesktop.changeDirectory {
          print(Path.Current)  // "/Users/nvzqz/Desktop"
      }
      
    • Getting a common ancestor between two paths with the <^> operator and commonAncestor(_:) method

    • Getting a resolved path with the * postfix operator

    • Getting an NSFileHandle for a File or Path

    • Path now conforms to SequenceType

      // Prints all of the paths in the user's home directory
      for path in Path.UserHome {
          print(path)
      }
      
    • Static readFromPath(_:) method for Readable types that returns Self

    • Path now conforms to StringInterpolationConvertible, which acts in the same way regular String interpolation works.

      let filePath: Path = "~/Desktop/File \(2)"
      print(filePath.rawValue)  // "~/Desktop/File 2"
      
    • A find method with a search depth that maps a function on each path found and returns the non-nil results.

      let documents = Path.UserDocuments.find(searchDepth: 1) { String($0) }
      
    • Initializers for NSString and NSBundle that take a Path

    • Getting an NSStream for a File or Path

    • File now conforms to Comparable according to size

    • FilePermissions struct for seeing the permissions of the current process for a given file.

      let swift: Path = "/usr/bin/swift"
      print(swift.filePermissions)  // FilePermissions[Read, Execute]
      

    Changes

    • Removed 'FK' prefix from FileKit types in an effort to make the library more Swifty
    • Removed FileType as a protocol for files
      • FileType is now an enumeration of types that a file can be.
      • File is now the standard way of interacting with files
    • Renamed FKError to FileKitError
    • Changed error parameters 'fromPath' and 'toPath' to 'from' and 'to' respectively
    • Changed the postfix operator to % for standardizing path
    • Renamed findPaths method to find for Path
    • Changed path url property to URL and made it non-optional
    • The find method now has -1 as its default searchDepth
    • writable property for WritableConvertible is now non-optional
    • Fix + operator implementation
    Source code(tar.gz)
    Source code(zip)
    FileKit.framework.zip(2.96 MB)
  • v1.7.0(Oct 10, 2015)

    Release Notes

    Changes

    • The file manager for FKPath instances is now defined by FKPath.FileManager, which is set to NSFileManager.defaultManager() by default
    • NSDictionary, NSArray, and NSData now conform to FKWritableToFile

    New Features

    • message property for FKError that improves error logging
    • FKPath now works with bookmark data
    • FKArrayFile and FKDataFile for NSArray and NSData respectively
    • FKReadableFromFile and FKWritableToFile protocols
    • FKWritableConvertible protocol with writable property to make the conforming type FKWritable
    • Static function FKPath.Volumes(_:) that returns an FKPath array of all mounted volumes
    • touch(_:) method for FKPath that creates a file at the path if it doesn't exist or updates the modification date
    • Properties for checking if the current process has certain privileges for an FKPath (isWritable, isReadable, isExecutable, isDeletable)
    Source code(tar.gz)
    Source code(zip)
    FileKit.framework.zip(1.73 MB)
  • v1.6.0(Sep 23, 2015)

  • v1.5.0(Sep 19, 2015)

    Release Notes

    New Features

    • FKPath now has an attributes property and properties for certain attributes
      • creationDate
      • modificationDate
      • ownerName
      • ownerID
      • groupName
      • groupID
      • extensionIsHidden
      • posixPermissions
      • fileReferenceCount
      • fileSize
      • filesystemFileNumber
      • fileType
    • Created FKPath.FileType enum that can also be initialized with a raw value. It makes working with the strings returned from the NSFileType key easier to work with.
    • FKPath now has an isSymbolicLink property
    Source code(tar.gz)
    Source code(zip)
    FileKit.framework.zip(934.43 KB)
  • v1.4.0(Sep 13, 2015)

  • v1.3.0(Sep 8, 2015)

    Release Notes

    New Features

    • FKPath now has its own pathExtension property

    • Method for finding paths has been added to FKPath

      You can find all paths with the "txt" extension five folders deep into the Desktop with:

      let textFiles = FKPath.UserDesktop.findPaths(searchDepth: 5) { path in
          path.pathExtension == "txt"
      }
      
    Source code(tar.gz)
    Source code(zip)
    FileKit.framework.zip(801.75 KB)
  • v1.2.0(Sep 7, 2015)

    Release Notes

    Changes

    • The symlink operators have been renamed to ~>> and ~>!

    New Features

    • Except for reading and writing, FKPath now has the same operations as FKFileType
    • Moving files using FKPath or FKFileType (->>, ->!)
    • Copying files using FKPath or FKFileType (+>>, +>!)
    Source code(tar.gz)
    Source code(zip)
    FileKit.framework.zip(780.57 KB)
  • v1.1.0(Sep 7, 2015)

    Release Notes

    Changes

    The components property of FKPath no longer takes into account a trailing "/" in the path.

    let hasTrailing: FKPath = "/Users/"
    let noTrailing:  FKPath = "/Users"
    print(hasTrailing.components.last == noTrailing.components.last)  // true
    

    New Features

    • exists property for FKPath
    • name property for FKFileType
    • createSymlinkToPath(_:) method for FKPath
    • >>> operator for FKPath symlinks
    • >>! operator for FKPath forced symlinks
    Source code(tar.gz)
    Source code(zip)
    FileKit.framework.zip(735.28 KB)
  • v1.0.0(Sep 6, 2015)

Owner
Nikolai Vazquez
conducts curses, breaks things, and uses the oxford comma
Nikolai Vazquez
Effortless ZIP Handling in Swift

ZIP Foundation is a library to create, read and modify ZIP archive files. It is written in Swift and based on Apple's libcompression for high performa

Thomas Zoechling 1.7k Sep 18, 2021
Swift framework for zipping and unzipping files.

Zip A Swift framework for zipping and unzipping files. Simple and quick to use. Built on top of minizip. Usage Import Zip at the top of the Swift file

Roy Marmelstein 2.1k Sep 17, 2021
A micro-framework for observing file changes, both local and remote. Helpful in building developer tools.

KZFileWatchers Wouldn't it be great if we could adjust feeds and configurations of our native apps without having to sit back to Xcode, change code, r

Krzysztof Zabłocki 1k Sep 14, 2021
ZipArchive is a simple utility class for zipping and unzipping files on iOS, macOS and tvOS.

SSZipArchive ZipArchive is a simple utility class for zipping and unzipping files on iOS, macOS and tvOS. Unzip zip files; Unzip password protected zi

ZipArchive 4.9k Sep 17, 2021
zip file I/O library for iOS, macOS and tvOS

ZipZap is a zip file I/O library for iOS, macOS and tvOS. The zip file is an ideal container for compound Objective-C documents. Zip files are widely

Glen Low 1.2k Aug 18, 2021