how to read data in rich content files using NSFilehandler - ios

This is my swift code simplified:
func readContent(url:NSURL!){
do {
let file: NSFileHandle? = try NSFileHandle(forReadingFromURL: url)
if (file != nil){
file?.seekToFileOffset(10)
let content=file!.readDataOfLength(5)
print(String(data: content, encoding: NSASCIIStringEncoding))
file!.closeFile()
}
}catch {
}
}
I am building a file reader, that could read text files and pdfs. I am using NSFileHandler because I need to keep track of the position where the reading is happening.
I am able to read text files without a problem. However with pdfs I am having two problems:
How do I get the type of encoding used to encore the pdf? NSASCIIStringEncoding for instance does not work fine with text file but not with the pdf file. I am getting strange characters. I imaging that there is a way to detect the encoding. I have been following https://developer.apple.com/library/ios/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/Introduction/Introduction.html and I haven't found anything addressing this issue on stack overflow.
Given the fact that pdfs may contain text, images and videos how do I identify these contents while reading.. I read that magic numbers might do it https://en.wikipedia.org/wiki/Magic_number_(programming)#Magic_numbers_in_files but I read that there are not advisable http://www.techrepublic.com/article/avoid-using-magic-numbers-and-string-literals-in-your-code/. In addition I have not yet found a guide on how to use them.
please note that it is important for me to keep track of the Offset while reading.

Related

iOS, Swift, Image Metadata, XMP, DJI Drones

I'm writing an iOS Swift app to fetch metadata from DJI drone images. I'm trying to access the Xmp.drone-dji.X metadata. The iOS/Swift CGImageSource and CGImageMetadata libraries/classes get almost all of the metadata out of the image but not the Xmp.drone-dji. When I get a list of tags, those tag/values are not listed. I know the tags/data are in the images because I've examined the images using exif, exiv2, etc.
Any suggestions?
Here is the code I'm using so far:
result.itemProvider.loadDataRepresentation(forTypeIdentifier: UTType.image.identifier)
{ data, err in
if let data = data {
let src = CGImageSourceCreateWithData(data as CFData,nil)!
let md = CGImageSourceCopyPropertiesAtIndex(src,0,nil) as! NSDictionary
let md2 = CGImageSourceCopyMetadataAtIndex(src,0,nil)
}
Thanks,
Bobby
So, after a lot of searching, trial and error, I have found an answer.
I was not able to get any of the CGImage swift libraries to extract this info for me.
Adobe has a c++ library that parses xmp/xml data out of images and it purports to support iOS. I didnt want the hassle of building c++ on iOS, importing that into Xcode and then dealing with the fact that thrown errors do not propagate well from c++/objectiveC to Swift.
So, at a high level, I did the following:
get the bytes of the raw image as CFData or Data then cast to a String
then use String.range() to find beginning of XML/XMP data in image
searching for substring <?xpacket begin
use String.range() to find end of XML/XMP data in image
using substring <?xpacket end.*?>
Extract the XML document out of image data String
Use Swift XMLParser class to parse the XML and then copying attributes and
elements as necessary. I just simply added what I wanted to already
existing Exif NSdictionary returned by CGImage classes.
Happy to answer questions on this approach. My code will eventually be uploaded to GitHub under OpenAthenaIOS project.
Bobby

How to generate smaller url bookmarks in Swift?

I want to create bookmarks for locally stored files so that the files can be tracked if they are moved to new locations.
My attempts to use Swift 3's NSURL function bookmarkData(options:includingResourceValuesForKeys:relativeTo) finds it obligatorily generating bookmark data objects that are almost a megabyte in size, even in cases in which the files themselves are orders of magnitude smaller than that.
For example, for a 4-byte text file, the following code produces 410kb bookmark data.
(Running in AppDelegate's applicationDidFinishLaunching, OS X, Xcode 8.2)
(Note that when I tried using NSURL.BookmarkCreationOptions.minimalBookmark, instead of .suitableForBookmarkFile, the output was only 0kb and I could not use it to track the original file.)
Similarly, bookmarking a 19kb .jpg file produces an 888kb bookmark.
Am I doing something wrong? If not, is there a way to get bookmarks that is not quite so greedy?
let url = URL(fileURLWithPath: "/Users/U/test.txt", isDirectory: false)
if let urlBookmark = try? url.bookmarkData(options: .suitableForBookmarkFile, includingResourceValuesForKeys: nil, relativeTo: nil) {
print("bookmark size = \(urlBookmark.count / 1024) kb")
}
Edit:
From a few further quick and dirty tests, I see that the size of the bookmark is fixed and is determined by the file's category rather than by the file's size:
.pages 479kb
.txt 419kb
.pdf 898kb
.numbers 309kb
.jpg 888kb
.png 915kb
.exe 342kb
.mp4 691kb
.mkv 594kb
Still, I would like to know if there is any way within those constraints to get even smaller bookmarks.

Looking for Xcode Swift examples to decompress gzipped Json data

I am trying to decompressed a Json data stream. I've found various decompression solutions, the native zlib seems easier, the other cocoa pod solutions produced new problems. The setting advised in native zlib inflate/deflate for swift3 on iOS seems working, the problem is what's next. I've thoroughly searched the net, only found C or Obj-C example codes but not Swift's. Thanks.
Another solution I tried was with https://github.com/mw99/DataCompression. But I had problem trying to set it up according to the instruction so look into the short codes and took out the part that I think should work for me, hard-coded some of the options. But no matter which algorithm I tried, perform() return nil.
I also tried unzip(), it failed at guard header >> 8 & 0b1111 == 0b1000. The web address automatic download a gzip file which can be decompressed into a Json file.
var routeFile: JsonRouteFile?
UIApplication.shared.isNetworkActivityIndicatorVisible = true
let urlRoute:URL = URL(string: "http://data.taipei/bus/ROUTE")!
DispatchQueue.global().async {
do {
let data:Data = try Data(contentsOf: urlRoute)
routeFile = try JSONDecoder().decode(JsonRouteFile?.self, from: data.decompress()!)
`
https://github.com/1024jp/GzipSwift works.
I didn't go through the enter installation though. Just dragged the file over.

iOS reading from a file

I'm trying to get my iPhone app to load text from a file into a string array, with 1 line from the file per array element.
I've created an input file as a text file using sublime text. I dragged the file (which is located inside of a folder inside of my project directory) into xCode into a folder in the same location in the project heirarchy.
I also tried adding it as a bundle (by copying the folder and renaming it with the .bundle extension), to no avail. Currently, my app has the file in 2 places (Obviously I plan to delete the unneeded version, but I'm not sure how this will work so I've left it for now).
I've written a function that I want to read my file, and assemble its contents into an array:
func readFromFile(filename: String) -> [String]? {
guard let theFile = Bundle.main.path( forResource: fileName, ofType: "txt") else {
return nil // ALWAYS returns nil here: Seems 'filename' can't be found?????
}
do { // Extract the file contents, and return them as a split string array
let fileContents = try String(contentsOfFile: theFile)
return fileContents.components(separatedBy: "\n")
} catch _ as NSError {
return nil
}
}
As it stands, the function always returns nil at the location commented in the code.
I've been working on this for ~6hrs (and tried every suggestion I could find on StackOverflow, google etc) and I'm just getting more and more confused by the differences between the various versions of Swift and intricacies of iOS development. I can't seem to find a consistent answer anywhere. I've checked the apple documentation but it's too high level with no example code for me to understand at my swift beginner level.
I also tried naming the file with a ".txt" extension but that didn't help either.
The file must certainly be named alert01.txt if you are going to refer to it as forResource: "alert01", ofType: "txt".
Loading from a bundle will not work. The file needs to be part of your project as shown in the first entry.
However, your code is not going to work because you have created a folder reference. That means the folder PanicAlertFiles is being copied with all its contents into your bundle. Your code will need to dive into that folder in order to retrieve your file. Use path(forResource:ofType:inDirectory:) to do that, or (if you don't want to have to code the file name explicitly) get the folder and then use the FileManager to examine its contents.

Delete File After contentsOfFile Load

I am loading an array of UIImage from the iOS Documents directory:
var images = [UIImage]()
for fileName in fileNames {
images.append(UIImage(contentsOfFile: "\(imagesPath)/\(fileName).png")!)
}
I'm going to continue using this array but I don't need the files anymore, so I go ahead and delete them:
for fileName in fileNames {
do {
try NSFileManager.defaultManager().removeItemAtPath("\(imagesPath)/\(fileName).png")
} catch {
print("Error")
}
}
When I do this, my array of UIImage is now invalid and gives me errors while trying to access them. Shouldn't this be in memory and not related to the files on disk?
I tried using the ".copy()" command on the images when I load them but that made no difference.
I have confirmed that the delete is the issue above because if I comment out that line the app works great with no errors. I only get errors accessing the array after I delete the files from disk.
Is there a way to sever this connection?
Edit: Per the correct answer from #Wain, the code works fine if I change it to:
var images = [UIImage]()
for fileName in fileNames {
let imgData = NSFileManager.defaultManager().contentsAtPath("\(imagesPath)/\(fileName).png")!
images.append(UIImage(data: imgData)!)
}
Doing this doesn't keep the link back to the file on disk.
The images haven't been displayed so the data hasn't fully been loaded yet, only enough to know the image details and size has been loaded. This is for memory efficiency. depending on the image format and usage different parts of data may be loaded at multiple different times.
If you load the file into NSData, ensuring that it isn't memory mapped, and create the image from that then the data and image should be unlinked from the underlying file. This is less memory efficient and it would be better to keep your current code and delete the files when you know you're finished with the images all together.

Resources