File couldn’t be opened because you don’t have permission to view it error - swift

I have Googled and poked around Stack Overflow and can't seem to find a solution for this. I have:
let fileURL = URL( string: "file:///Users/me/file.txt" )
var rawDataString: String
var errorString: String?
do {
rawDataString = try String( contentsOf: fileURL!, encoding: String.Encoding.utf8 )
} catch let error as NSError {
errorString = error.description
print( errorString! )
return
}
and it's erroring out with
Error Domain=NSCocoaErrorDomain Code=257 "The file “file.txt” couldn’t
be opened because you don’t have permission to view it."
Permissions are read for all users:
$ ls -al file.txt
-rw-r--r--# 1 me staff 348306 Dec 13 2016 file.txt
Any ideas would be most welcome.

Anyone coming across this thread, #LeoDabus pointed me to where to turn off sandbox, which worked:
He also cleaned up my code a bit:
let fileURL = URL( fileURLWithPath: "/Users/me/file.txt" )
var rawDataString: String
var errorString: String?
do {
rawDataString = try String( contentsOf: fileURL, encoding: .utf8 )
} catch let error as NSError {
errorString = error.description
rawDataString = ""
return
}

(For iOS)
Sadly #Dribbler´s answer didn't work for me because I didn't have App Sandbox enabled and it still didn't work. In my case I used the UIDocumentPickerViewController and I was unable to access the file.
Adding url.startAccessingSecurityScopedResource() before working with the file resolved the issue for me.
Here is an example of the didPickDocumentsAt delegate function from a UIDocumentPickerViewController:
guard let url = urls.first else {
return
}
guard url.startAccessingSecurityScopedResource() else { // Notice this line right here
return
}
do {
let data = try Data(contentsOf: url)
} catch let error {
print(error.localizedDescription)
}
After adding that line it worked for me.

I actually was not able to get the preferred answers above to work for me in swift playground.
Another solution is just to create a command line app in Xcode. Then paste the above and it should work fine.

Related

Issues updating/appending a string to the end of a file in Swift

I am working on an app where I am trying to write data to a file. Basically the user can set the save directory and then I want to be able to check to see if the file exists. If it doesn't then create it and write the data. If it does exist I want to update/append a string to the end of the file. I have tried following many examples and guides online and it seems everyone is doing this differently. I apologize ahead of time if I am missing something super simple or if this has been asked a hundred times.
I have mostly been working off of this example with no success
Append text or data to text file in Swift
#IBAction func addVariance(_ sender: Any) {
let csvString = "08-06-2019,10:00 AM,10:23 AM,23,Offline,Test"
let directoryURL = URL(string: "/Users/username/Desktop/CSVtest")
let fileURL = directoryURL!.appendingPathComponent("/variances.csv")
let data = NSData(data: csvString.data(using: String.Encoding.utf8, allowLossyConversion: false)!)
if FileManager.default.fileExists(atPath: fileURL.path) {
var err:NSError?
if let fileHandle = try? FileHandle(forUpdating: fileURL) {
fileHandle.seekToEndOfFile()
fileHandle.write(data as Data)
fileHandle.closeFile()
}
else {
print("Can't open fileHandle \(String(describing: err))")
}
}
else {
var err:NSError?
do {
try data.write(to: URL(fileURLWithPath: fileURL.path), options: .atomic)
} catch {
print(error)
}
}
}
When trying to run this function when there is a file in the folder named "variances.csv" I get "Can't open fileHandle nil".
I have tried break points and print() lines. It doesn't seem to be getting past "if let fileHandle = try? FileHandle(forUpdating: fileURL)" and I can't figure out why. fileURL is not nil.
When I try running this function outputting to an empty directory I get.
"Error Domain=NSCocoaErrorDomain Code=513 "You don’t have permission to save the file “variances.csv” in the folder “CSVtest”." UserInfo={NSFilePath=/Users/username/Desktop/CSVtest/variances.csv, NSUnderlyingError=0x600000c9eaf0 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}"

FileHandle not accepting my URLs for write access

I'd like to open a uniquely named output file for writing either plist or data, but not having any luck in getting a handle using either URL routine of init(fileURLWithPath:) or init(string:)
func NewFileHandleForWritingFile(path: String, name: String, type: String, outFile: inout String?) -> FileHandle? {
let fm = FileManager.default
var file: String? = nil
var uniqueNum = 0
while true {
let tag = (uniqueNum > 0 ? String(format: "-%d", uniqueNum) : "")
let unique = String(format: "%#%#.%#", name, tag, type)
file = String(format: "%#/%#", path, unique)
if false == fm.fileExists(atPath: file!) { break }
// Try another tag.
uniqueNum += 1;
}
outFile = file!
do {
let fileURL = URL.init(fileURLWithPath: file!)
let fileHandle = try FileHandle.init(forWritingTo: fileURL)
print("\(file!) was opened for writing")
//set the file extension hidden attribute to YES
try fm.setAttributes([FileAttributeKey.extensionHidden: true], ofItemAtPath: file!)
return fileHandle
} catch let error {
NSApp.presentError(error)
return nil;
}
}
debugger shows
which for this URL init routine adds the scheme (file://) but otherwise the same as the other, and I'd like to prefer the newer methods which throw reutrning (-1) when just using paths. The error thrown (2) is an ENOENT (no such entity!?) as I need a handle to write to I'm confused how else to get one? The sample path is a new folder created at desktop to triage.
Unlike the previous answer, I recommend using Data's write(to:options:) API instead of FileManager's createFile(atPath:contents:attributes:), because it is a URL-based API, which is generally to be preferred over path-based ones. The Data method also throws an error instead of just returning false if it fails, so if something goes wrong, you can tell the user why.
try Data().write(to: fileURL, options: [])
I would also suggesting replacing the path-based FileManager.fileExists(atPath:) with the URL-based checkResourceIsReachable():
if false == ((try? fileURL.checkResourceIsReachable()) ?? false)
You can't create a file handle to a non-existent file. That is what is causing the ENOENT error.
Use FileManager createFile(atPath:contents:attributes:) to create the file just before creating the file handle.
do {
fm.createFile(atPath: file!, contents: nil, attributes: [FileAttributeKey.extensionHidden: true])
let fileURL = URL(fileURLWithPath: file!)
let fileHandle = try FileHandle(forWritingTo: fileURL)
print("\(file!) was opened for writing")
return fileHandle
} catch let error {
NSApp.presentError(error)
return nil;
}

Alamofire download in MacOS. Looks fine, progresses is working, but no file?

I have Alamofire added through cocoapods and I have a method going to download a zip file (approx 50Mb).
While downloading everything looks perfect. I can see in Activity Monitor that 50Mb is downloaded for my app, I can see the progressbar zinging across. But I can never find the file.
Right now I have it set to use the current directory, but have tried others just in case. I have even searched the entire drive by data modified and never find anything.
Here is my code.
func downloadAndInstall(){
log.info("Downloading and Installing.....")
displayToUser(content: "Downloading and Installing.....")
let urlString = updatePackageURL //(This is http://xxxx.com/xxxxpackage.zip)
let fileManager = FileManager.default
currentDir = fileManager.currentDirectoryPath
let fileURL: URL = URL(string: currentDir + "/package.zip")!
let destination: DownloadRequest.DownloadFileDestination = { _, _ in (fileURL, []) }
log.info("FILEURL: \(fileURL)")
var progressValues: [Double] = []
var response: DefaultDownloadResponse?
Alamofire.download(urlString, to: destination)
.downloadProgress { progress in
progressValues.append(progress.fractionCompleted)
log.info("Latest Progress Value: \(progress.fractionCompleted)")
self.progBar.doubleValue = progress.fractionCompleted
}
.response { resp in
response = resp
if progressValues.last != 1.0 {
//backout of the process, something went wrong
log.debug("Something went wrong downloading the file. Close and try again.")
self.displayToUser(content: "Something went wrong downloading the file. Close and try again.")
self.exitpoorly()
}
else{
log.info("Download Finished")
self.displayToUser(content: "Download Finished")
self.extractpackage()
}
}
var previousProgress: Double = progressValues.first ?? 0.0
for progress in progressValues {
previousProgress = progress
}
if let lastProgressValue = progressValues.last {
log.info("Current Download Value: \(lastProgressValue, 1.0)")
} else {
//Fail
}
}
I'd suggest checking for any errors, e.g.:
Alamofire.download(urlString, to: destination)
.downloadProgress { progress in
...
}
.response { response in
guard response.error == nil else {
//backout of the process, something went wrong
log.debug("Something went wrong downloading the file. Close and try again.")
log.debug(response.error!.localizedDescription)
...
self.exitpoorly()
return
}
log.info("Download Finished")
...
}
Maybe the app is sandboxed, or perhaps you don't have permissions for that folder. It's hard to say without seeing the error.

AVMIDIPlayer DLSBankManager::AddBank: Bank load failed

When I use AVMIDIPlayer to play a MusicSequence with only one note message. Most of times it works fine but sometimes it has no sound and logged as below:
DLSBankManager::AddBank: Bank load failed
Error Domain=com.apple.coreaudio.avfaudio Code=-10871 "(null)"
It works well on iOS9, but when i test it on iOS10 it runs into this issue.
I'm sure that the sf2 sound bank file url is set properly.
I paste the code as below:
func playAVMIDIPlayerPreview(_ musicSequence:MusicSequence) {
guard let bankURL = Bundle.main.url(forResource: "FluidR3 GM2-2", withExtension: "sf2") else {
fatalError("soundbank file not found.")
}
var status = OSStatus(noErr)
var data:Unmanaged<CFData>?
status = MusicSequenceFileCreateData (musicSequence,
MusicSequenceFileTypeID.midiType,
MusicSequenceFileFlags.eraseFile,
480, &data)
if status != OSStatus(noErr) {
print("bad status \(status)")
}
if let md = data {
let midiData = md.takeUnretainedValue() as Data
do {
try self.midiPlayerPreview = AVMIDIPlayer(data: midiData, soundBankURL: bankURL)
} catch let error as NSError {
print("Error \(error)")
}
data?.release()
self.midiPlayerPreview?.play({ () -> Void in
self.midiPlayerPreview = nil
self.musicSequencePreview = nil
})
}
}
The error is occur on this line:
try self.midiPlayerPreview = AVMIDIPlayer(data: midiData, soundBankURL: bankURL)
Try setting the global variable errno to 0 errno = 0 before loading the soundfont with
try self.midiPlayerPreview = AVMIDIPlayer(data: midiData, soundBankURL: bankURL)
We experienced the same issue and at the same time this one.
So we tried to apply the fix of the other issue to this one and it just worked.

xcode error 'consecutive statements on a line must be separated by' when creating endpoint URL for REST API datatask

I am a beginner, trying to code a POST datarequest to post a vote to the 'rating' field of a Drupalnode (so that users can rate movies). I have followed online guides, carefully copying the syntax, but in Xcode am receiving this error for for this line:
let movieEndpoint: String = https://www.examplesitename.com/film1
The red error message is "consecutive statements on a line must be separated by a ';'
The error highlights the ':' after https, and suggests "fix it" with an ';' but changing it to https;www.examplesitename.com/film1 then brings up another red error 'expected expression' (and doesn't seem correct as it is a URL)
For context, below is my code, (which I hope will work to post my data request but haven't been able to check yet)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)
let movieEndpoint: String = https://www.sitename.com/film1
guard let movieURL = NSURL(string: movieEndpoint) else {
print("Error: cannot create URL")
return
}
let movieUrlRequest = NSMutableURLRequest(URL: movieURL)
movieUrlRequest.HTTPMethod = "POST"
let task = session.dataTaskWithRequest(movieUrlRequest, completionHandler:{ _, _, _ in })
let newRating = ["rating": 50, "userId": 1,]
let jsonRating: NSData
do {
jsonRating = try NSJSONSerialization.dataWithJSONObject(newRating, options: [])
movieUrlRequest.HTTPBody = jsonRating
} catch {
print("Error: cannot create JSON from todo")
return
}
movieUrlRequest.HTTPBody = jsonRating
task.resume()
}
Thank you for any help you can give me.
The proper way to declare a String in Swift is to add " " around the string.
Fix your code like this:
let movieEndpoint: String = "https://www.sitename.com/film1"