{"id":19278767,"url":"https://github.com/admkopec/lsfilewrapper","last_synced_at":"2025-07-25T16:42:56.927Z","repository":{"id":53844261,"uuid":"196554880","full_name":"admkopec/LSFileWrapper","owner":"admkopec","description":"📁 A Swift and Objective-C replacement for NSFileWrapper that loads / saves content on-demand with minimal memory footprint. Understands how to save / serialize objects like NSData, UIImage, NSImage, NSDictionary, etc...","archived":false,"fork":false,"pushed_at":"2021-06-15T12:04:36.000Z","size":125,"stargazers_count":17,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-10-30T17:13:24.808Z","etag":null,"topics":["filewrapper","ios","macos","nsdata","nsdocument","nsfilewrapper","nsimage","objective-c","swift","uidocument","uiimage"],"latest_commit_sha":null,"homepage":"","language":"Objective-C","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/admkopec.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":"2019-07-12T09:54:58.000Z","updated_at":"2023-11-19T20:30:32.000Z","dependencies_parsed_at":"2022-08-17T14:51:42.769Z","dependency_job_id":null,"html_url":"https://github.com/admkopec/LSFileWrapper","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/admkopec%2FLSFileWrapper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/admkopec%2FLSFileWrapper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/admkopec%2FLSFileWrapper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/admkopec%2FLSFileWrapper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/admkopec","download_url":"https://codeload.github.com/admkopec/LSFileWrapper/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223883713,"owners_count":17219270,"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":["filewrapper","ios","macos","nsdata","nsdocument","nsfilewrapper","nsimage","objective-c","swift","uidocument","uiimage"],"created_at":"2024-11-09T21:11:41.446Z","updated_at":"2024-11-09T21:11:41.979Z","avatar_url":"https://github.com/admkopec.png","language":"Objective-C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 📁 LSFileWrapper\n![Platforms](https://img.shields.io/badge/platform-ios%20%7C%20macos-lightgrey)\n[![GitHub](https://img.shields.io/badge/license-MIT-green)](LICENSE)\n[![Swift Package Manager](https://img.shields.io/badge/package%20manager-compatible-brightgreen.svg?logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iNjJweCIgaGVpZ2h0PSI0OXB4IiB2aWV3Qm94PSIwIDAgNjIgNDkiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDYzLjEgKDkyNDUyKSAtIGh0dHBzOi8vc2tldGNoLmNvbSAtLT4KICAgIDx0aXRsZT5Hcm91cDwvdGl0bGU+CiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz4KICAgIDxnIGlkPSJQYWdlLTEiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPgogICAgICAgIDxnIGlkPSJHcm91cCIgZmlsbC1ydWxlPSJub256ZXJvIj4KICAgICAgICAgICAgPHBvbHlnb24gaWQ9IlBhdGgiIGZpbGw9IiNEQkI1NTEiIHBvaW50cz0iNTEuMzEwMzQ0OCAwIDEwLjY4OTY1NTIgMCAwIDEzLjUxNzI0MTQgMCA0OSA2MiA0OSA2MiAxMy41MTcyNDE0Ij48L3BvbHlnb24+CiAgICAgICAgICAgIDxwb2x5Z29uIGlkPSJQYXRoIiBmaWxsPSIjRjdFM0FGIiBwb2ludHM9IjI3IDI1IDMxIDI1IDM1IDI1IDM3IDI1IDM3IDE0IDI1IDE0IDI1IDI1Ij48L3BvbHlnb24+CiAgICAgICAgICAgIDxwb2x5Z29uIGlkPSJQYXRoIiBmaWxsPSIjRUZDNzVFIiBwb2ludHM9IjEwLjY4OTY1NTIgMCAwIDE0IDYyIDE0IDUxLjMxMDM0NDggMCI+PC9wb2x5Z29uPgogICAgICAgICAgICA8cG9seWdvbiBpZD0iUmVjdGFuZ2xlIiBmaWxsPSIjRjdFM0FGIiBwb2ludHM9IjI3IDAgMzUgMCAzNyAxNCAyNSAxNCI+PC9wb2x5Z29uPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+)](https://github.com/apple/swift-package-manager)\n[![Build iOS](https://github.com/admkopec/LSFileWrapper/workflows/iOS/badge.svg)](https://github.com/admkopec/LSFileWrapper/actions?query=workflow%3A%22iOS%22)\n[![Build macOS](https://github.com/admkopec/LSFileWrapper/workflows/macOS/badge.svg)](https://github.com/admkopec/LSFileWrapper/actions?query=workflow%3A%22macOS%22)\n\nReplacement for NSFileWrapper that loads / saves content on-demand. It is specifically designed to handle large packages / bundles or directories with multiple file entries. It requires minimal memory footprint, as it doesn't try to load everything into memory (unlike Apple's NSFileWrapper), but rather tries to memory map the single files only when they're actively being used. This library also has built-in convenience methods for saving / serializing objects like NSData, UIImage, NSImage, NSDictionary, etc...\n\n## 💻 Requirements\nLSFileWrapper works on Mac OS X 10.7+ and iOS 8.0 or newer. The Xcode project contains two framework targets for:\n* 💻 macOS (10.7 or greater)\n* 📱 iOS (8.0 or greater)\n\n## 📖 Usage\n* [Creating new wrappers](#creating-new-wrappers)\n* [Loading from disk](#loading-from-disk)\n* [Writing to disk](#writing-to-disk)\n- [Adding contents](#adding-contents)\n- [Reading contents](#reading-contents)\n- [Updating contents](#updating-contents)\n* [Removing wrappers](#removing-wrappers)\n* [Getting child wrappers](#getting-child-wrappers)\n\n### Creating new wrappers\nTo create a new LSFileWrapper use `-initDirectory` for directory wrappers or `-initFile` for regular file wrappers.\nThese wrappers and all of their contents will be stored entirely in the memory until any of the write methods gets called.\n\n```objective-c\nLSFileWrapper* newDirectoryWrapper = [[LSFileWrapper alloc] initDirectory];\nLSFileWrapper* newRegularFileWrapper = [[LSFileWrapper alloc] initFile];\n```\n*Swift:*\n```swift\nlet newDirectoryWrapper = LSFileWrapper(directory: ())\nlet newRegularFileWrapper = LSFileWrapper(file: ())\n```\n### Loading from disk\nTo load an existing wrapper from disk use `-initWithURL`. When boolean `NO` is passed to isDirectory, the init method checks and automatically creates correct LSFileWrapper type based on passed url.\n\n```objective-c\nNSURL* url;\n\nLSFileWrapper* existingWrapper = [[LSFileWrapper alloc] initWithURL: url isDirectory: NO];\n```\n\n*Swift:*\n```swift\nlet url: URL\n\nlet existingWrapper = LSFileWrapper(with: url, isDirectory: false)\n```\n### Writing to disk\n\u003e **_Notice:_** Writing methods should only be called on the top most wrapper – a wrapper that has no parents.\n\nTo write the wrapper to disk call `-writeToURL` or `-writeUpdatesToURL`, the difference between the two being that updates will update the cached wrapper location and remove changes from memory, so use this only in situations like autosave. For duplicate operations use `-writeToURL`. Only the main wrapper can be written to disk – the wrapper that has no parents. If the write is issued as part of NSDocument's save routine there's a convenience method `-writeToURL forSaveOperation` that automatically calls `-writeToURL` or `-writeUpdatesToURL` based on save operation and also handles document backups (versioning) and url switches on save as.\n```objective-c\nLSFileWrapper* mainWrapper;\nNSURL* url;\n\n// Saves all contents to disk at specified URL\n[mainWrapper writeToURL: url];\n\n// Dumps all changes to the specified URL, make sure that the LSFileWrapper contents are present at the URL, \n// otherwise the write method could result in partial contents on the disk and potential loss of data.\n[mainWrapper writeUpdatesToURL: url];\n```\n*NSDocument (macOS only):*\n```objective-c\nLSFileWrapper* mainWrapper;\n\n-(BOOL)writeToURL:(NSURL *)url forSaveOperation:(NSSaveOperationType)saveOperation originalContentsURL:(NSURL *)absoluteOriginalContentsURL error:(NSError __autoreleasing *)outError {\n    [url startAccessingSecurityScopedResource]; // Recommended on OS X 10.7.3 and newer\n    BOOL success = [mainWrapper writeToURL: url forSaveOperation: saveOperation originalContentsURL: absoluteOriginalContentsURL backupDocumnetURL: [self backupFileURL] outError: outError];\n    [url stopAccessingSecurityScopedResource];\n    return success;\n}\n```\n\n*Swift:*\n```swift\nlet mainWrapper: LSFileWrapper\nlet url: URL\n\n// Saves all contents to disk at specified URL\nmainWrapper.write(to: url)\n\n// Dumps all changes to the specified URL, make sure that the LSFileWrapper contents are present at the URL, \n// otherwise the write method could result in partial contents on the disk and potential loss of data.\nmainWrapper.writeUpdates(to: url)\n```\n\n*NSDocument (macOS only):*\n```swift\nlet mainWrapper: LSFileWrapper\n\noverride func write(to url: URL, for saveOperation: SaveOperationType, originalContentsURL absoluteOriginalContentsURL: URL?) throws {\n    _ = url.startAccessingSecurityScopedResource()\n    try mainPackageWrapper.write(to: url, for: saveOperation, originalContentsURL: absoluteOriginalContentsURL, backupDocumentURL: self.backupFileURL)\n    url.stopAccessingSecurityScopedResource()\n}\n```\n### Adding contents\n\u003e **_Notice:_** Directory wrappers only.\n\nTo add a file wrapper to an existing directory wrapper use `-addFileWrapper` or `-setFileWrapper`, the difference between the two being that *add* will suffix a filename with 2, 3, 4, etc… if the wrapper with the same name already exists and return the final filename, *set* will overwrite any existing file wrappers. \n`-addContent` and `-setContent` work the same way, but create the file wrapper for you.\n```objective-c\nLSFileWrapper* directoryWrapper;\n\n// Adds an empty directory with preferred name\nNSString* folderName = [directoryWrapper addFileWrapper: [[LSFileWrapper alloc] initDirectory] withFilename: @\"Empty Directory Name\"];\n\n// Adds and overrides any wrappers matching the filename\n[directoryWrapper setFileWrapper: [[LSFileWrapper alloc] initDirectory] withFilename: @\"Empty Directory Name\"];\n\n// Adds a new text file\nNSString* fileName = [directoryWrapper addContent: @\"Hello, World!\" withFilename: @\"hello.txt\"];\n\n// Adds and overrides any files matching the filename. This method could also be used when changes are made to the file\n[directoryWrapper setContent: @\"Hello, World!\" withFilename: @\"hello.txt\"];\n```\n\n*Swift:*\n```swift\nlet directoryWrapper: LSFileWrapper\n\n// Adds an empty directory with preferred name\nlet folderName = directoryWrapper.add(wrapper: LSFileWrapper(directory: ()) withFilename: \"Empty Directory Name\")\n\n// Adds and overrides any wrappers matching the filename\ndirectoryWrapper.set(wrapper: LSFileWrapper(directory: ()) withFilename: \"Empty Directory Name\")\n\n// Adds a new text file. Content has to be of Objective-C type, i.e. NSString, NSData... or casted with `as` operator\nlet filename = directoryWrapper.add(content: NSString(\"Hello, World!\"), withFilename: \"hello.txt\")\n\n// Adds and overrides any files matching the filename. This method can be used when changes are made to the file\ndirectoryWrapper.set(content: \"Hello, World!\" as NSString, withFilename: \"hello.txt\")\n```\n### Reading Contents\n\u003e **_Notice:_** File wrappers only.\n\nTo retrieve contents of a regular file wrapper use one of various convenience methods: `-data`, `-string`, `-dictionary`, `-image`.\n```objective-c\nLSFileWrapper* fileWrapper;\n\nNSData* data = [fileWrapper data];\nNSString* string = [fileWrapper string];\n```\n\n*Swift:*\n```swift\nlet fileWrapper: LSFileWrapper\n\nlet optionalData = fileWrapper.data()\nlet optionalString = fileWrapper.string()\n```\n### Updating Contents\n\u003e **_Notice:_** File wrappers only.\n\nTo update the contents of a regular file wrapper use `-updateContent`, named `update(newContent:)` in Swift.\n```objective-c\nLSFileWrapper* fileWrapper;\n\n[fileWrapper updateContent: @\"Hello, World!\"];\n```\n\n*Swift:*\n```swift\nlet fileWrapper: LSFileWrapper\n\nfileWrapper.update(newContent: \"Hello, World!\" as NSString)\n```\n### Removing wrappers\n\u003e **_Notice:_** Directory wrappers only.\n\nTo remove a file wrapper from existing wrapper use `-removeFileWrapper` or `removeFileWrapperWithPath`, named `removeWrapper()` or `removeWrapper(with:)` in Swift.\n```objective-c\nLSFileWrapper* directoryWrapper;\n\n// Using a path, can also contain \"/\" for subfolder search, all children can be removed\n[directoryWrapper removeFileWrapperWithPath: @\"hello.txt\"];\n\n// Using an instance of a wrapper. Path can also contain \"/\" for subfolder search, however only 'first' children can be removed.\nLSFileWrapper* wrapperToRemove = [directoryWrapper fileWrapperWithPath: @\"hello.txt\"];\nif (wrapperToRemove) {\n    [directoryWrapper removeFileWrapper: wrapperToRemove];\n}\n```\n\n*Swift:*\n```swift\nlet directoryWrapper: LSFileWrapper\n\n// Using a path, can also contain \"/\" for subfolder search, all children can be removed\ndirectoryWrapper.removeWrapper(with: \"hello.txt\")\n\n// Using an instance of a wrapper. Path can also contain \"/\" for subfolder search, however only 'first' children can be removed.\nif let wrapperToRemove = directoryWrapper.wrapper(with: \"hello.txt\") {\n    directoryWrapper.removeWrapper(wrapperToRemove)\n}\n```\n### Getting child wrappers\n\u003e **_Notice:_** Directory wrappers only.\n\nTo get a wrapper from a directory wrapper call `-fileWrapperWithPath`, named `wrappers(with:)` in Swift, this will also traverse all children based on supplied path.\n```objective-c\nLSFileWrapper* directoryWrapper;\n\nLSFileWrapper* wrapper = [directoryWrapper fileWrapperWithPath: @\"hello.txt\"];\n```\n\n*Swift:*\n```swift\nlet directoryWrapper: LSFileWrapper\n\nlet wrapper = directoryWrapper.wrapper(with: \"hello.txt\")\n```\n\nTo get all first-degree child wrappers from a directory wrapper call `-fileWrappersInPath`, named `wrappers(in:)` in Swift, this will also traverse all children based on supplied path.\n```objective-c\nLSFileWrapper* directoryWrapper;\n\nNSArray\u003cLSFileWrapper*\u003e *wrappers = [directoryWrapper fileWrappersInPath: @\"/\"];\n```\n\n*Swift:*\n```swift\nlet directoryWrapper: LSFileWrapper\n\nlet wrappers = directoryWrapper.wrappers(in: \"/\")\n```\n## ⚖️ License\nLSFileWrapper is distributed under the [MIT license](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadmkopec%2Flsfilewrapper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fadmkopec%2Flsfilewrapper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadmkopec%2Flsfilewrapper/lists"}