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
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"}}"
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;
}
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.
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.
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"