{"id":13995160,"url":"https://github.com/kareman/FileSmith","last_synced_at":"2025-07-22T21:32:10.554Z","repository":{"id":56911267,"uuid":"76396382","full_name":"kareman/FileSmith","owner":"kareman","description":"A strongly typed Swift library for working with local files and directories.","archived":false,"fork":false,"pushed_at":"2020-07-13T17:10:09.000Z","size":1408,"stargazers_count":27,"open_issues_count":8,"forks_count":3,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-11-25T22:45:35.087Z","etag":null,"topics":["files","filesystem-library","swift","swift-library","symbolic-links"],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kareman.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-12-13T20:37:46.000Z","updated_at":"2024-07-11T14:52:14.000Z","dependencies_parsed_at":"2022-08-21T04:20:46.758Z","dependency_job_id":null,"html_url":"https://github.com/kareman/FileSmith","commit_stats":null,"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kareman%2FFileSmith","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kareman%2FFileSmith/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kareman%2FFileSmith/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kareman%2FFileSmith/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kareman","download_url":"https://codeload.github.com/kareman/FileSmith/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":227177794,"owners_count":17743167,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["files","filesystem-library","swift","swift-library","symbolic-links"],"created_at":"2024-08-09T14:03:16.845Z","updated_at":"2024-11-29T17:31:06.649Z","avatar_url":"https://github.com/kareman.png","language":"Swift","funding_links":[],"categories":["Swift"],"sub_categories":[],"readme":"[Run shell commands](https://github.com/kareman/SwiftShell) | [Parse command line arguments](https://github.com/kareman/Moderator) | Handle files and directories\n\n---\n\n[![Build Status](https://travis-ci.org/kareman/FileSmith.svg?branch=master)](https://travis-ci.org/kareman/FileSmith) ![Platforms](https://img.shields.io/badge/platforms-macOS%20%7C%20iOS%20%7C%20tvOS%20%7C%20WatchOS%20%7C%20Linux-lightgrey.svg)\n\n# FileSmith\n\nA strongly typed Swift library for working with local files and directories.\n\nIt differentiates between file paths and directory paths, and between paths and actual files and directories, because the programmer knows which are which and when the compiler knows it too it can be much more helpful. \n\nSee also:\n\n- [API documentation](https://kareman.github.io/FileSmith/)\n- [Why FileSmith was created](https://nottoobadsoftware.com/blog/swift/filesmith-type-safe-file-handling-in-swift)\n\n## Features\n\n- [x] Separate types for file paths, directory paths, reading files, writing files, and directories.\n- [x] Use Swifts native error handling.\n- [x] List the contents of directories (recursively if needed).\n- [x] Filter with glob wildcard patterns.\n- [x] Sandbox mode prohibits changes outside of the current working directory.\n- [x] Write text to files the same way you use Swift's `print` function.\n\n## Terms\n\n**Path:**  \nThe location of an item _which may or may not exist_ in the local file system. It is either a [DirectoryPath](https://kareman.github.io/FileSmith/Structs/DirectoryPath.html), [FilePath](https://kareman.github.io/FileSmith/Structs/FilePath.html) or [AnyPath](https://kareman.github.io/FileSmith/Structs/AnyPath.html).\n\n**File:**  \nAn existing regular file or something _file-like_ which you can read from and/or write to, like streams, pipes or sockets. Or symbolic links to any of these.\n\n**Directory:**  \nAn existing directory or a symbolic link to a directory. Basically anything you can `cd` into in the terminal.\n\n**Item:**  \n(for lack of a better term)  \nA file or a directory. Anything with a path in the file system.\n\n## Safety first\n\nWhen `Directory.sandbox == true` (and it is by default) you can only change files or create new files and directories if they are under the current working directory. Trying to make changes elsewhere throws an error.\n\n## Usage\n\n#### Change current working directory\n\n```swift\nDirectoryPath.current = \"/tmp\"\nDirectory.current = Directory.createTempDirectory()\n```\n\n#### [Paths](https://kareman.github.io/FileSmith/Protocols/Path.html)\n\n```swift\n// common functionality\nlet dirpath = DirectoryPath(\"dir/dir1\")\nvar filepath: FilePath = \"file.txt\"\nfilepath = FilePath(base: \"dir\", relative: \"file.txt\")\nfilepath = FilePath(\"dir/file.txt\")\n\nfilepath.relativeString\nfilepath.base?.string\nfilepath.absoluteString\nfilepath.string // relativeString ?? absoluteString\nfilepath.name\nfilepath.nameWithoutExtension\nfilepath.extension\n\n// DirectoryPath only\ndirpath.append(file: \"file.txt\")  // FilePath(\"dir/dir1/file.txt\")\ndirpath.append(directory: \"dir2\") // DirectoryPath(\"dir/dir1/dir2\")\ndirpath.isAParentOf(filepath)\n```\n\n#### Create\n\n```swift\nvar dir1 = try dirpath.create(ifExists: .replace)\nvar dir2 = try Directory(create: \"dir/dir2\", ifExists: .throwError)\nvar dir3 = try dir2.create(directory: \"dir3\", ifExists: .open) // dir/dir2/dir3\n\nvar file1_edit = try filepath.create(ifExists: .open)\nlet file2_edit = try WritableFile(create: \"file2.txt\", ifExists: .open)\nlet file3_edit = try dir1.create(file: \"file3.txt\", ifExists: .open) // dir/dir1/file3\n```\n\n#### Open\n\n```swift\ndir1 = try dirpath.open()\ndir2 = try Directory(open: \"dir/dir2\")\ndir3 = try dir2.open(directory: \"dir3\")\n\nlet file1 = try filepath.open()\nlet file2 = try ReadableFile(open: \"file2.txt\")\nlet file3 = try dir1.open(file: \"file3.txt\")\n```\n\n#### Read/Write\n\n```swift\nfile1_edit.encoding = .utf16 // .utf8 by default\nfile1_edit.write(\"some text...\")\nfile1_edit.print(\"Just like Swift's own 'print' function.\")\nfile1_edit.print(2, \"words\", separator: \"-\", terminator: \"\")\nfile2.write(to: \u0026file1_edit)\n\nlet contents: String = file3.read()\nfor line in file3.lines() { // a lazy sequence\n\t// ...\n}\nwhile let text = file3.readSome() {\n\t// read pipes etc. piece by piece, instead of waiting until they are closed.\n}\n```\n\n#### Search/Filter\n\n```swift\nDirectory.current.files(recursive: true)       // [file2.txt, dir/file1.txt, dir/dir1/file3.txt]\ndir1.files(\"*3.*\", recursive: true)            // [file3.txt]\nDirectory.current.directories(recursive: true) // [dir, dir/dir1, dir/dir2, dir/dir2/dir3]\n```\n\n#### Symbolic links\n\n```swift\nlet dir1_link = try Directory(createSymbolicLink: \"dir1_link\", to: dir1, ifExists: .open)\nlet dir2_link = try dir1.create(symbolicLink: \"dir2_link\", to: dir2, ifExists: .open)\nlet file1_link = try ReadableFile(createSymbolicLink: \"file1_link\", to: file1, ifExists: .open)\nlet file2_link = try dir2.create(symbolicLink: \"file2_link\", to: file2, ifExists: .open) as ReadableFile\n```\n\n#### Misc\n\n```swift\n// the path of a file or directory\nfile1.path // FilePath\ndir1.path  // DirectoryPath\n\n// remove files and directories\ntry file1_edit.delete()\ntry dir1.delete()\n```\n\n## Types\n\nWhen opening files symbolic links are always followed, so the type of a file is never .symbolicLink, but can be .brokenSymbolicLink for symbolic links whose targets do not exist.\n\n```swift\nFileType(\"file.txt\")\nFileType(filepath)\n\npublic enum FileType: Equatable, Hashable {\n\tcase regularFile\n\tcase directory\n\tcase characterSpecial\n\tcase blockSpecial\n\tcase socket\n\tcase brokenSymbolicLink\n\tcase namedPipe\n\tcase unknown\n}\n```\n\n## Installation\n\n### [Swift Package Manager](https://github.com/apple/swift-package-manager)\n\nAdd `.package(url: \"https://github.com/kareman/FileSmith\", from: \"0.3.0\")` to your Package.swift:\n\n```swift\nimport PackageDescription\n\nlet package = Package(\n\tname: \"somename\",\n\tdependencies: [\n\t\t.package(url: \"https://github.com/kareman/FileSmith\", from: \"0.3.0\")\n\t\t]\n\t)\n```\n\nand run `swift build`.\n\n### [CocoaPods](https://cocoapods.org/)\n\nAdd `FileSmith` to your `Podfile`.\n\n```ruby\npod \"FileSmith\", git: \"https://github.com/kareman/FileSmith.git\"\n```\n\nThen run `pod install` to install it.\n\n## License\n\nReleased under the MIT License (MIT), http://opensource.org/licenses/MIT\n\nKåre Morstøl, [NotTooBad Software](https://nottoobadsoftware.com)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkareman%2FFileSmith","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkareman%2FFileSmith","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkareman%2FFileSmith/lists"}