I'm working on a Mac desktop app and trying to run a shell script. I'm getting hung up on setting a launch path for the task. Here's the code:
let path = fileURL.deletingLastPathComponent().relativePath
//set new filename
let strNewFileName = fileURL.deletingPathExtension().lastPathComponent.appending(".html")
let newPath = path + "/" + strNewFileName
//create script
var strScript = "pandoc -s -o "
strScript.append(newPath)
strScript.append(" ")
strScript.append(fileURL.absoluteString)
//set storage path
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
var documentPath:URL = URL(string: documentsPath)!
documentPath.appendPathComponent("pandoc.sh")
var myURLComponents = URLComponents()
myURLComponents.scheme = "file"
myURLComponents.path = documentPath.absoluteString
do {
//write file
try strScript.write(to: myURLComponents.url!, atomically: true, encoding: String.Encoding.utf8)
//run script
let myTask = Process()
myTask.launchPath = "/usr/bin/env"
myTask.arguments = [strScript]
let myPipe = Pipe()
myTask.standardOutput = myPipe
myTask.launch()
let data = myPipe.fileHandleForReading.readDataToEndOfFile()
let output = NSString(data: data, encoding: String.Encoding.utf8.rawValue)
print(output!)
} catch {
print(error.localizedDescription)
}
This throws a no such file error:
env: pandoc -s -o /Users/stevensuranie/Desktop/MarkdownFiles/targeting-params-ios.html file:///Users/stevensuranie/Desktop/MarkdownFiles/targeting-params-ios.md: No such file or directory
Any help would be appreciated.
This line cannot work
var documentPath:URL = URL(string: documentsPath)!
URL(string is for URL strings including the scheme (file:// or https://), for file system paths you must use URL(fileURLWithPath.
However if you use the URL related API of FileManager you can avoid the init method at all.
A similar issue is absoluteString, never call it on a file system URL, use always path.
A second fatal issue is that each shell argument must be an item in the arguments array and the executable must be specified with the full path
//create script
let scriptArguments = ["/path/to/pandoc", "-s", "-o", newPath, fileURL.path]
//set storage path
let documentsURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
let scriptURL = documentsURL.appendingPathComponent("pandoc.sh")
The following lines are redundant
var myURLComponents = URLComponents()
myURLComponents.scheme = "file"
myURLComponents.path = documentPath.absoluteString
The write the string to scriptURL
do {
//write file
try strScript.write(to: scriptURL, atomically: true, encoding: .utf8)
...
myTask.arguments = scriptArguments
And finally don't use NS... classes in Swift
let output = NSString(data: data, encoding: String.Encoding.utf8.rawValue)
Use the native equivalent
let output = String(data: data, encoding: .utf8)
Related
This Code:
let csvString = self.generateCSV()
let tmpURL = try FileManager.default.url(for: .itemReplacementDirectory,
in: .userDomainMask,
appropriateFor: nil,
create: true)
let tempFileUrl = tmpURL.appendingPathComponent("App-DigiAufklaerung-\(self.formatDateToPrecision(Date())).csv")
let data = csvString.data(using: .utf8)
try data?.write(to: tempFileUrl,
options: .atomic)
self.csvFile = tempFileUrl
(I thought) should create a tmp file, from which i can then share the cdv through AirDrop, but the creation of the tmpDir fails, what am i doing wrong here?
This error message was printed several times:
CFURLSetTemporaryResourcePropertyForKey failed because it was passed an URL which has no scheme
I have this code:
let image = UIImage(data: downloadedImage!)
let convertImage = UIImagePNGRepresentation(image!)
let pathUIDImage = self.getDocumentsDirectory().appendingPathComponent(playersUID + "Image")
try? convertImage!.write(to: pathUIDImage) //working
let playersUIDImageVersion = "1"
var pathUIDImageVersion = self.getDocumentsDirectory().appendingPathComponent(playersUID + "ImageVersion")
try? playersUIDImageVersion.write(to: pathUIDImageVersion) //error
The error is:
Cannot convert value of type "URL" to expected instrument type "inout_"
When I replace try? playersUIDImageVersion to try? convertImage! the error is gone. Is there a difference between writing different types of values to the directory? Thank you. Below the function getDocumentsDirectory
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let documentsDirectory = paths[0]
return documentsDirectory
}
The write function of String is different, it requires additional parameters atomically and encoding.
try? playersUIDImageVersion.write(to: pathUIDImageVersion, atomically: true, encoding: .utf8)
In such a case retype the function and see what Xcode suggests for code completion.
Besides it's highly recommended to use always an appropriate file extension (.png, .txt).
I am making a func that edits a text file in the Users/johnDoe Dir.
let filename = "random.txt"
let filePath = "/Users/johnDoe"
let replacementText = "random bits of text"
do {
try replacementText.write(toFile: filePath, atomically: true, encoding: .utf8)
}catch let error as NSError {
print(error: + error.localizedDescription)
}
But I want to be able to have the path universal. Something like
let fileManager = FileManager.default
let downloadsURL = FileManager.default.urls(for: .downloadsDirectory, in: .userDomainMask).first! as NSURL
let downloadsPath = downloadsURL.path
but for the JohnDoe folder. I haven't been able to find any documentation on how to do this. The closest thing I could find mentioned using NSHomeDirectory(). And I am not sure how to use it in this context.
when I try adding it like...
let fileManager = FileManager.default
let downloadsURL = FileManager.default.urls(for: NSHomeDirectory, in: .userDomainMask).first! as NSURL
let downloadsPath = downloadsURL.path
I get an error:
"Cannot Convert value of type 'String' to expected argument type 'FileManager.SearchPathDirectory'"
I've tried it .NSHomeDirectory, .NSHomeDirectory(), NShomeDirectory, NShomeDirectory()
You can use FileManager property homeDirectoryForCurrentUser
let homeDirURL = FileManager.default.homeDirectoryForCurrentUser
If you need it to work with earlier OS versions than 10.12 you can use
let homeDirURL = URL(fileURLWithPath: NSHomeDirectory())
print(homeDirURL.path)
There should be an easier way but -- at worst -- this should work:
let filePath = NSString(string: "~").expandingTildeInPath
Swift 5 (and maybe lower)
let directoryString: String = NSHomeDirectory()
let directoryURL: URL = FileManager.default.homeDirectoryForCurrentUser
Maybe
FileManager.homeDirectoryForCurrentUser: URL
It's listed as "beta" for 10.12, though.
I am recording video to a file with this code:
print(documentsPath)
//var/mobile/Containers/Data/Application/FFB207E7-36CC-4C53-A2E2-5FADC7C23A18/Documents/gymnastVideos/test.mp4
let filePath = NSURL(fileURLWithPath: documentsPath)
videoFileOutput.startRecording(toOutputFileURL: filePath as URL!, recordingDelegate: recordingDelegate)
and have verified that the file exists, however, when I try to open the file to check if anything is being saved there, I return an error. The code:
var documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
documentsPath.append("/gymnastVideos")
let filePath = URL(fileURLWithPath: documentsPath)
do {
let directoryContents = try FileManager.default.contentsOfDirectory(at: filePath, includingPropertiesForKeys: nil, options: [])
print(directoryContents)
print("!")
} catch let error as NSError {
print(error.localizedDescription)
//The file “gymnastVideos” couldn’t be opened.
print("!!")
}
Why can't I open the file, and what do I need to change in my code to be able to open the file?
a. How should I get all the txt files in directory?
i got a path of directory and now i should find all the txt files and change every one a little.
i try to run over all the files:
let fileManager = NSFileManager.defaultManager()
let enumerator:NSDirectoryEnumerator = fileManager.enumeratorAtPath(folderPath)
while let element = enumerator?.nextObject() as? String {
}
}
but I stuck there. How can I check if the filetype is text?
b. When i get to a directory (in the directory I run), I want get in and search there too, and in the end get out to the place I was and continue.
a is much more important to me but if I get an answer to b too it will be nice.
a. Easy and simple solution for Swift 3:
let enumerator = FileManager.default.enumerator(atPath: folderPath)
let filePaths = enumerator?.allObjects as! [String]
let txtFilePaths = filePaths.filter{$0.contains(".txt")}
for txtFilePath in txtFilePaths{
//Here you get each text file path present in folder
//Perform any operation you want by using its path
}
Your task a is completed by above code.
When talking about b, well you don't have to code for it because we are here using a enumerator which gives you the files which are inside of any directory from your given root directory.
So the enumerator does the work for you of getting inside a directory and getting you their paths.
You can use for .. in syntax of swift to enumerate through NSEnumerator.
Here is a simple function I wrote to extract all file of some extension inside a folder.
func extractAllFile(atPath path: String, withExtension fileExtension:String) -> [String] {
let pathURL = NSURL(fileURLWithPath: path, isDirectory: true)
var allFiles: [String] = []
let fileManager = NSFileManager.defaultManager()
if let enumerator = fileManager.enumeratorAtPath(path) {
for file in enumerator {
if let path = NSURL(fileURLWithPath: file as! String, relativeToURL: pathURL).path
where path.hasSuffix(".\(fileExtension)"){
allFiles.append(path)
}
}
}
return allFiles
}
let folderPath = NSBundle.mainBundle().pathForResource("Files", ofType: nil)
let allTextFiles = extractAllFile(atPath: folder!, withExtension: "txt") // returns file path of all the text files inside the folder
I needed to combine multiple answers in order to fetch the images from a directory and I'm posting my solution in Swift 3
func searchImages(pathURL: URL) -> [String] {
var imageURLs = [String]()
let fileManager = FileManager.default
let keys = [URLResourceKey.isDirectoryKey, URLResourceKey.localizedNameKey]
let options: FileManager.DirectoryEnumerationOptions = [.skipsPackageDescendants, .skipsSubdirectoryDescendants, .skipsHiddenFiles]
let enumerator = fileManager.enumerator(
at: pathURL,
includingPropertiesForKeys: keys,
options: options,
errorHandler: {(url, error) -> Bool in
return true
})
if enumerator != nil {
while let file = enumerator!.nextObject() {
let path = URL(fileURLWithPath: (file as! URL).absoluteString, relativeTo: pathURL).path
if path.hasSuffix(".png"){
imageURLs.append(path)
}
}
}
return imageURLs
}
and here is a sample call
let documentsDirectory = FileManager.default.urls(for:.documentDirectory, in: .userDomainMask)[0]
let destinationPath = documentsDirectory.appendingPathComponent("\(filename)/")
searchImages(pathURL: projectPath)
Swift 4
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let url = URL(fileURLWithPath: documentsPath)
let fileManager = FileManager.default
let enumerator: FileManager.DirectoryEnumerator = fileManager.enumerator(atPath: url.path)!
while let element = enumerator.nextObject() as? String, element.hasSuffix(".txt") {
// do something
}
let fileManager = NSFileManager.defaultManager()
let enumerator:NSDirectoryEnumerator = fileManager.enumeratorAtPath(folderPath)
while let element = enumerator?.nextObject() as? String where element.pathExtension == "txt" {
// element is txt file
}
let fileManager = NSFileManager.defaultManager()
let enumerator:NSDirectoryEnumerator = fileManager.enumeratorAtPath(folderPath!)!
while let element = enumerator.nextObject() as? String {
if (element.hasSuffix(".txt")) { // element is a txt file }
}