I'm trying to unzip some archives in a macOS app using the ZipFoundation library. The files are located on the desktop, I've confirmed the paths are correct and that the file exists.
I have this code:
let fileManager = FileManager()
let sourceURL = URL(fileURLWithPath: monetizeZiPFile.absoluteString)
var destinationURL = URL(fileURLWithPath: dirBuildURL.absoluteString)
destinationURL.appendPathComponent("directory")
do {
try fileManager.createDirectory(at: destinationURL, withIntermediateDirectories: true, attributes: nil)
try fileManager.unzipItem(at: monetizeZiPFile, to: dirBuildURL)
} catch {
print("Extraction of ZIP archive failed with error:\(error)")
}
I receive this error for the unzipItem method:
CFURLResourceIsReachable failed because it was passed an URL which has no scheme
Extraction of ZIP archive failed with error:Error Domain=NSCocoaErrorDomain Code=260
"The file “00-monetize.zip” couldn’t be opened because there is no such file." UserInfo={NSFilePath=/Users/xxxxxxxx/Desktop/Componize-Builds/DOC-8621/Monetize/00-monetize.zip}
Do I have to be within the project directories for ZipFoundation to work?
For paths, do not use absoluteString, use path.
Related
I have saved one zip file in my app, which is having .json files in it.
I have to unzip this zip file at some path and read the file after unzip.
I tried using package managers like ZipFoundation
If I run the app on my mac with OS 10.15.2 (macOS Catalina) I get the following output
"Extraction of ZIP archive failed with error:Error Domain=NSCocoaErrorDomain Code=513 "You don’t have permission to save the file “directory” in the folder “Macintosh HD”." UserInfo={NSFilePath=/directory, NSUnderlyingError=0x600002f39530 {Error Domain=NSPOSIXErrorDomain Code=13 "Permission denied"}}"
if I run the app on device (iPhone XS Max iOS 13.3.1) I get the following error,
Extraction of ZIP archive failed with error:Error Domain=NSCocoaErrorDomain Code=513 "You don’t have permission to save the file “directory” in the folder “System#snap-8290536”." UserInfo={NSFilePath=/directory, NSUnderlyingError=0x2811d54d0 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}
This is my code
import ZIPFoundation
func unarchiveFile(){
let fileManager = FileManager()
let currentWorkingPath = fileManager.currentDirectoryPath
var sourceURL = URL(fileURLWithPath: "/Users/sagarchavan/Documents/Project/Swift-POC/iOS-CD-POCs/CDSwiftDemo/")
//var sourceURL = URL(fileURLWithPath:currentWorkingPath)
sourceURL.appendPathComponent("countryList.zip")
print("source url is :- :\(sourceURL)")
var destinationURL = URL(fileURLWithPath: currentWorkingPath)
destinationURL.appendPathComponent("directory")
print("destinationURL is :- :\(destinationURL)")
do {
try fileManager.createDirectory(at: destinationURL, withIntermediateDirectories: true, attributes: nil)
try fileManager.unzipItem(at: sourceURL, to: destinationURL)
} catch {
print("Extraction of ZIP archive failed with error:\(error)")
}
}
Can you please help me out to get out from this issue.
I need to unzip the zip file.
for sourceURL I tried both, by giving currentWorkingPath and by giving actual path to file. but both the time i get same error.
#note :- I don't want to use any pods or Carthage. I want default code or external dependancies are from package managers only.
Any help will be appreciated.
Thank you.
All Thanks to #vadian
I used URL(fileURLWithPath: currentWorkingPath)
Here is my sample code which is working well now,
func unarchiveFile(){
let fileManager = FileManager()
let currentWorkingPath = "/Users/sagarchavan/Documents/Project/Swift-POC/iOS-CD-POCs/CDSwiftDemo/CDSwiftDemo/Zipfile/"
var sourceURL = URL(fileURLWithPath:currentWorkingPath)
sourceURL.appendPathComponent("countryList.zip")
var destinationURL = URL(fileURLWithPath: currentWorkingPath)
destinationURL.appendPathComponent("unzipData")
do {
try fileManager.createDirectory(at: destinationURL, withIntermediateDirectories: true, attributes: nil)
try fileManager.unzipItem(at: sourceURL, to: destinationURL)
parseJSONFromFile(destinationPath: destinationURL)
} catch {
print("Extraction of ZIP archive failed with error:\(error)")
}
}
I'm just starting learning Swift and to teach myself I'm making a simple command line app. It will eventually connect to an online data source but initially I want to load data from a file. I've seen various guides on reading the contents of a file in Swift but none of them seem to work for me. Here is my app so far:
import Foundation
// Set the file path
let path = "/Users/username/workspace/Swift/sis/sis/data.json"
do {
// Get the contents
let contents = try String(contentsOfFile: path, encoding: .utf8)
print(contents)
}
catch let error as NSError {
print("Ooops! Something went wrong: \(error)")
}
Running it outputs:
Ooops! Something went wrong: Error Domain=NSCocoaErrorDomain Code=260 "The file “data.json” couldn’t be opened because there is no such file." UserInfo={NSFilePath=/Users/username/workspace/Swift/sis/sis/data.json, NSUnderlyingError=0x100e19a50 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}
However on the terminal:
$ ls -l /Users/username/workspace/Swift/sis/sis/data.json
-rwxrwxrwx# 1 username staff 165563 16 Jan 17:14 /Users/username/workspace/Swift/sis/sis/data.json
(yeah I relaxed the permissions somewhat just in case that was the problem)
The only slightly anomalous thing I noticed (aside from the inaccurate assertion that the file doesn't exist) was that when I copy and past the path from the XCode output into iTerm2 it puts spaces between each path component:
(pasted as an image as copying it and pasting it back into this form seems to hide the spaces - this is probably irrelevant anyway)
Any help figuring this out would be really appreciated!
I copied your code, downloaded a sample json file to my desktop, and renamed it to example_ 1.json (I included a space inside the file name).
import Foundation
// Set the file path
let path = "/Users/username/Desktop/example_ 1.json"
do {
// Get the contents
let contents = try String(contentsOfFile: path, encoding: .utf8)
print(contents)
}
catch let error as NSError {
print("Ooops! Something went wrong: \(error)")
}
It successfully printed the file. It also worked when I defined contents as a NSString.
let contents = try NSString(contentsOfFile: path,
encoding: String.Encoding.ascii.rawValue)
I am using Swift 4.2.1
you can not read if your command line app is sandboxed. what you can do is to add this file in your project and set path of file by looking the full path of file in identity inspector.
let path = "/Users/snx/EmailReplacer/EmailReplacer/shared_domains_staging.json"
do {
let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe)
let jsonResult = try JSONSerialization.jsonObject(with: data, options: .mutableLeaves)
if let jsonResult = jsonResult as? Dictionary<String, AnyObject> {
print(jsonResult)
}
} catch {
print(error)
}
I've been having problem with using share extension to get a file and unzip it into my app group folder.
Here is the code:
for attachment in content.attachments as! [NSItemProvider] {
if attachment.hasItemConformingToTypeIdentifier(contentType){
attachment.loadItem(forTypeIdentifier: contentType, options: nil) { (data, error) in
let fileManager = FileManager()
let url = data as! URL
let destinationURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.KakaoAnalyzer")?.appendingPathComponent("KakaoFilesTemp")
do {
try fileManager.createDirectory(at: destinationURL!, withIntermediateDirectories: true, attributes: nil)
try fileManager.unzipItem(at: url, to: destinationURL!)
self.mergeFiles()
print("SUCCESSFULLY UNZIPPED")
} catch {
print(error.localizedDescription)
print("UNZIP FAILED")
}
}
}
}
This is part of my didSelectPost()
I'm using share extension to get a ZIP file via share, and ZIPFoundation to unzip it into my destination folder which is my app group with this extension and my main project.
This code runs fine and unzips successfully in a simulator, but when I run it on my phone, I get an error:
The file "FILENAME" couldn't be opened because there is no such file
when there clearly should be one, and
Failed to determine whether URL "FILEURL" is managed by a file provider.
I've tried moving the file at the url to my documentDirectory, but it produces error:
"FILE" couldn't be moved because you don't have permission to access "appGroupFolder"
Does anyone how to solve this? Any help would be greatly appreciated!
My ultimate question is about saving a screenshot from an AppleTV application using XCTest and Swift4 (running on a MacBook paired to the TV device), but I'm having trouble even writing a simple text string to a local file. If I can get this simple file-save working, I'm hoping I can resolve the screenshot issue. (Apologies for making this look like two questions but they appear to be related and resulted from my troubleshooting efforts.)
First, here's what I'm trying to do with a screenshot, based on sample code I found somewhere online:
let appshot = XCUIApplication().windows.firstMatch.screenshot()
let shotpath = FileManager.default.urls(for: .downloadsDirectory, in: .userDomainMask)[0].appendingPathComponent("appshot.png")
let shotpathUrl = URL(string: "file://\(shotpath)")
print("Saving to: \(shotpath)")
do {
try appshot.pngRepresentation.write(to: shotpathUrl!)
} catch {
print("Failed saving screenshot due to \(error)")
}
This gives me the following output:
Saving to: file:///var/mobile/Containers/Data/Application/77D52C66-353B-4029-97D5-48E6BAE35C92/Downloads/appshot.png
Failed saving screenshot due to Error Domain=NSCocoaErrorDomain Code=4 "The file “appshot.png” doesn’t exist." UserInfo={NSFilePath=///var/mobile/Containers/Data/Application/77D52C66-353B-4029-97D5-48E6BAE35C92/Downloads/appshot.png, NSUnderlyingError=0x1c405bc60 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}
Of course, the file doesn't exist because that's the file I'm trying to create. But /var/mobile doesn't exist on my laptop either -- it looks like the path FileManager is building may exist on the AppleTV device, but I want it on my laptop where my test script is executing.
So I backed out to a much more simple case, and even this is giving me problems:
let str = "This is a test"
let path = "file:///Users/haljor/foo.txt"
let pathUrl = URL(string: path)!
print("Path: \(path)")
print("URL: \(pathUrl)")
do {
try str.write(to: pathUrl, atomically: true, encoding: .utf8)
} catch {
print("Caught error writing to \(pathUrl): \(error)")
}
And here's the output:
Path: file:///Users/haljor/foo.txt
URL: file:///Users/haljor/foo.txt
Caught error writing to file:///Users/haljor/foo.txt: Error Domain=NSCocoaErrorDomain Code=4 "The folder “foo.txt” doesn’t exist." UserInfo={NSURL=file:///Users/haljor/foo.txt, NSUserStringVariant=Folder, NSUnderlyingError=0x1c40553f0 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}
Here, it looks like it's trying to write to a folder at the path I specified, not a file. Clearly there's something I'm not understanding in each of these cases.
I don't really have a preference for whether I use a fully-specified path or something using FileManager -- it just needs to land somewhere on my laptop (not the TV device). What am I missing?
You can add an attachment to the test case and save it to disk too. The problem was that Downloads folder may not exist in the container yet. The best way to handle this is via init-once property:
var downloadsFolder: URL = {
let fm = FileManager.default
let folder = fm.urls(for: .downloadsDirectory, in: .userDomainMask)[0]
var isDirectory: ObjCBool = false
if !(fm.fileExists(atPath: folder.path, isDirectory: &isDirectory) && isDirectory.boolValue) {
try! fm.createDirectory(at: folder, withIntermediateDirectories: false, attributes: nil)
}
return folder
}()
func test() {
let appshot = XCUIScreen.main.screenshot()
let attachment = XCTAttachment(screenshot: appshot)
attachment.lifetime = .keepAlways
self.add(attachment)
// Save to container
let url = downloadsFolder.appendingPathComponent("appshot.png")
try! appshot.pngRepresentation.write(to: url)
}
If you want to view the attachment, right-click on the test case, select Jump to Report and expand the tree. You will see the screenshot eventually:
I've noticed that FileManager's methods for moving and copying items behave differently. fileManager.moveItem(at: src, to: dst) throws error if dst directory has immutable attribute:
Error Domain=NSCocoaErrorDomain Code=513 "“src” couldn’t be moved because you don’t have permission to access “dst”." UserInfo={NSSourceFilePathErrorKey=dst, NSUserStringVariant=(
Move
), NSDestinationFilePath=dst, NSFilePath=src, NSUnderlyingError=0x108b0e190 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}
Instead fileMangaer.copyItem(at: src, to: dst) doesn't throw any errors. It's only output to console a message:
Open on dst: Operation not permitted
Is there are any way to copy file with better error handling?
Running on macOS 10.12.5
UPD:
Code example:
let dir = "/private/tmp/file-manager-test"
let file = "/private/tmp/file1"
do {
try FileManager.default.createDirectory(atPath: dir, withIntermediateDirectories: true, attributes: nil)
FileManager.default.createFile(atPath: file, contents: Data(), attributes: nil)
try FileManager.default.setAttributes([.immutable: true], ofItemAtPath: dir)
let fname = (file as NSString).lastPathComponent
let dst = (dir as NSString).appendingPathComponent(fname)
try FileManager.default.copyItem(atPath: file, toPath: dst)
} catch let e {
print("\(e)")
}
It works as expected in playground. But if you run this code in applicationDidFinishLaunching() method you will see no exceptions.
UPD2:
I've found similar case on OpenRadar: https://openradar.appspot.com/32083596
Looks like this is system's bug related to OS_ACTIVITY_DT_MODE environment variable.