iPhone - NSData from local file's URL - iphone

I have a NSURL object which gives me the path of a local file (in documents folder). I want to populate an NSData object with the contents of this file. Tried using dataWithContentsOfURL: but this fails. I know the file exists because the iPhone SDK returns the path.
Can someone please tell me how I can get an NSData object from the URL of a local file?
Thanks.

// Given some file path URL: NSURL *pathURL
// Note: [pathURL isFileURL] must return YES
NSString *path = [pathURL path];
NSData *data = [[NSFileManager defaultManager] contentsAtPath:path];
Swift code:
let data = FileManager.default.contents(atPath: path)

To get this work you just need to do:
NSURL *imgPath = [[NSBundle mainBundle] URLForResource:#"search" withExtension:#"png"];
NSString*stringPath = [imgPath absoluteString]; //this is correct
//you can again use it in NSURL eg if you have async loading images and your mechanism
//uses only url like mine (but sometimes i need local files to load)
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:stringPath]];
UIImage *ready = [[[UIImage alloc] initWithData:data] autorelease];

Make sure your local URL starts with "file://"
then you would just have to do this:
NSData *fileData = [NSData dataWithContentsOfFile:fileURL.path];

For swift3 I found answer from following URL helpful
( I was getting following path , after capturing image using phonegap plugin
file:///var/mobile/Containers/Data/Application/B64B06DE-7976-45CF-9BE2-661F0F309A06/tmp/abcded.jpg )
https://stackoverflow.com/a/41043447/6383908
if let videoURL = URL(string: urlString), let videodata = try? Data(contentsOf: videoURL) {
//Add code of Alamofire here
}

guard let data = FileManager.default.contents(atPath: path) else
{ ...

Related

Converting NSString which was read from a file to NSURL to create AVAsset in Swift

At Obj-C we were reading a file and converting its NSString content to NSURL to get AVAsset which was saved as absoluteString beforehand.
audioAssetURL = [NSURL URLWithString:[readNSString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
audioAsset = [AVAsset assetWithURL: audioAssetURL];
But In Swift once again saved NSURL as absoluteString can not be used as NSURL and creates error.
let urlString: NSString = readNSString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!
let url = NSURL(fileURLWithPath: urlString as String)
audioAsset = AVAsset(URL: url )as AVAsset
The error message we are getting is that "Error: this application, or a library it uses, has passed an invalid numeric value (NaN, or not-a-number) to CoreGraphics API and this value is being ignored.Please fix this problem."

How to access image from Asset URL in iPhone?

I am getting asset URL from NSURL* localUrl = (NSURL *)[info valueForKey:UIImagePickerControllerReferenceURL]; and I saved it in a local database. And at the time of retrieving I have got an string and I have convert it into NSURL through NSURL *url1 = [NSURL URLWithString:image_path]; but when I get NSData from this URL through NSData *myData = [NSData dataWithContentsOfURL:url1]; it return NULL. Can anyone help me to get NSData and convert it into image.
You can not convert it direct. You will have to use ALAsset Block. Here is the complete description for same thing.
display image from URL retrieved from ALAsset in iPhone

Reading Image from the Local Folder in Objective C

I need to Read a Image from the specific URL .
It works fine with WWW . but it returns a nil when the URL pointing the Local Folder .
// Works
NSString *sampleData = #"http://blogs-images.forbes.com/ericsavitz/files/2011/05/apple-logo2.jpg";
// Returns nil
NSString *sampleData = #"USER/user2/...";
Note :
I am changing the NSString to NSURL and creating the UIImage .
NSURL *url = [NSURL URLWithString: data];
UIImage *image = [UIImage imageWithData: [NSData dataWithContentsOfURL:url]];
You are supplying a relative pathname for the file URL. That relative pathname is interpreted relative to the current working directory of the running application, which isn't guaranteed to be anything in particular, and so is almost certainly not what you want.
You can either supply an absolute path - one that starts with '/' - or set your app's current working directory to something explicit, like your user's Documents folder.
you probably should have a look into the NSBundle Class.
Methods like
- (NSURL *)URLForResource:(NSString *)name withExtension:(NSString *)extension subdirectory:(NSString *)subpath
or
- (NSString *)pathForResource:(NSString *)name ofType:(NSString *)extension
is probably what you want
First of all, you can NOT read file from such path you given: "USER/user2/...", the file must in your App bundle or in your App's sandbox.
Second, check your path string if there was some texts need to be encoded in URL. Try:
NSURL *url = [NSURL URLWithString:[data stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
Also, if the url is not nil, you should also check if your [NSData dataWithContentsOfURL:url]; is returning nil. If so, it means your URL is not correct so the method cannot find your file.
P.S., You are mistyping your image create code, you should call alloc before imageWithData:.
You should do something like to get the local url :
NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *pngFilePath = [NSString stringWithFormat:#"%#/%#", docDir, nameOfFile];
and finaly, load your image :
UIImage *image = [UIImage imageWithContentsOfFile:pngFilePath];
Try these instead
NSString *path = #"USER/user2/.../xxx.xxx";
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL isFileExist = [fileManager fileExistsAtPath:path];
UIImage *image;
if (isFileExist) {
image = [[UIImage alloc] initWithContentsOfFile:path];
}
else {
// do something.<br>
}

Accessing Local file using NSURL

I am trying to access an XML file store in the resources directory. I am using NSURL to access this file using NSURLConnection( this file is going to be swapped out for a remote service in the future).
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL
URLWithString:#"file:///XMLTest.xml"]
cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
NSURLConnection *connection=[[NSURLConnection alloc] initWithRequest:request delegate:self];
if (connection) {
// Create the NSMutableData to hold the received data.
// receivedData is an instance variable declared elsewhere.
response = [[NSMutableData data] retain];
} else {
NSLog(#"Could not create connection");
}
The class that starts the connection implements the NSURLConnection methods:
connection:willCacheResponse:
connection:didReceiveData:
connectionDidFinishLoading:
connectionDidFinishLoading:
Once I launch this the simulator dies, no messages are printed to the console so I am at a loss for where to look. Any ideas, or am I just doing this completely wrong?
Trying to load anything from the filesystem root is wrong, wrong, wrong. Definitely wrong on the device, and probably wrong on the simulator. The resources directory should be accessed via the NSBundle class.
For example, to get a URL for a file called "Data.txt" in the resources, use the following:
NSURL *MyURL = [[NSBundle mainBundle]
URLForResource: #"Data" withExtension:#"txt"];
If you want to get a URL from a path (say, because you created a file in NSTemporaryDirectory() and you need to get that as a URL) you can easily do so by using NSURL's fileURLWithPath method:
NSString* tempPath = NSTemporaryDirectory();
NSString* tempFile = [tempPath stringByAppendingPathComponent:fileName];
NSURL* URL = [NSURL fileURLWithPath:tempFile];
Much easier than +URLWithString: and other methods.
This would also work:
Obj-C
NSString *path = [[NSBundle mainBundle] pathForResource:#"XMLTest" ofType:#"xml"];
Swift 5
let url = Bundle.main.url(forResource: "XMLTest", withExtension: "xml")!
Hope this helps!
You can try this
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"file://localhost/Users/userName/Desktop/XMLTest.xml"]];
here assuming file is in desktop.
Swift 3:
let myFileName = "somefilename"
let myURL = Bundle.main.url(forResource: myFileName, withExtension: "png")

How can you read a files MIME-type in objective-c

I am interested in detecting the MIME-type for a file in the documents directory of my iPhone application. A search through the docs did not provide any answers.
It's a bit hacky, but it should work, don't know for sure because I'm just guessing at it
There are two options:
If you just need the MIME type, use the timeoutInterval: NSURLRequest.
If you want the data as well, you should use the commented out NSURLRequest.
Make sure to perform the request in a thread though, since it's synchronous.
NSString* filePath = [[NSBundle mainBundle] pathForResource:#"imagename" ofType:#"jpg"];
NSString* fullPath = [filePath stringByExpandingTildeInPath];
NSURL* fileUrl = [NSURL fileURLWithPath:fullPath];
//NSURLRequest* fileUrlRequest = [[NSURLRequest alloc] initWithURL:fileUrl];
NSURLRequest* fileUrlRequest = [[NSURLRequest alloc] initWithURL:fileUrl cachePolicy:NSURLCacheStorageNotAllowed timeoutInterval:.1];
NSError* error = nil;
NSURLResponse* response = nil;
NSData* fileData = [NSURLConnection sendSynchronousRequest:fileUrlRequest returningResponse:&response error:&error];
fileData; // Ignore this if you're using the timeoutInterval
// request, since the data will be truncated.
NSString* mimeType = [response MIMEType];
[fileUrlRequest release];
Add MobileCoreServices framework.
Objective C:
#import <MobileCoreServices/MobileCoreServices.h>
NSString *fileExtension = [myFileURL pathExtension];
NSString *UTI = (__bridge_transfer NSString *)UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)fileExtension, NULL);
NSString *contentType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)UTI, kUTTagClassMIMEType);
Swift:
import MobileCoreServices
func mimeType(fileExtension: String) -> String? {
guard !fileExtension.isEmpty else { return nil }
if let utiRef = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, fileExtension as CFString, nil) {
let uti = utiRef.takeUnretainedValue()
utiRef.release()
if let mimeTypeRef = UTTypeCopyPreferredTagWithClass(UTI, kUTTagClassMIMEType) {
let mimeType = MIMETypeRef.takeUnretainedValue()
mimeTypeRef.release()
return mimeType as String
}
}
return nil
}
The accepted answer is problematic for large files, as others have mentioned. My app deals with video files, and loading an entire video file into memory is a good way to make iOS run out of memory. A better way to do this can be found here:
https://stackoverflow.com/a/5998683/1864774
Code from above link:
+ (NSString*) mimeTypeForFileAtPath: (NSString *) path {
if (![[NSFileManager defaultManager] fileExistsAtPath:path]) {
return nil;
}
// Borrowed from https://stackoverflow.com/questions/5996797/determine-mime-type-of-nsdata-loaded-from-a-file
// itself, derived from https://stackoverflow.com/questions/2439020/wheres-the-iphone-mime-type-database
CFStringRef UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (CFStringRef)[path pathExtension], NULL);
CFStringRef mimeType = UTTypeCopyPreferredTagWithClass (UTI, kUTTagClassMIMEType);
CFRelease(UTI);
if (!mimeType) {
return #"application/octet-stream";
}
return [NSMakeCollectable((NSString *)mimeType) autorelease];
}
Prcela solution did not work in Swift 2. The following simplified function will return the mime-type for a given file extension in Swift 2:
import MobileCoreServices
func mimeTypeFromFileExtension(fileExtension: String) -> String? {
guard let uti: CFString = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, fileExtension as NSString, nil)?.takeRetainedValue() else {
return nil
}
guard let mimeType: CFString = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType)?.takeRetainedValue() else {
return nil
}
return mimeType as String
}
I was using the answer provided by slf in a cocoa app (not iPhone) and noticed that the URL request seems to be reading the entire file from disk in order to determine the mime type (not great for large files).
For anyone wanting to do this on the desktop here is the snippet I used (based on Louis's suggestion):
NSString *path = #"/path/to/some/file";
NSTask *task = [[[NSTask alloc] init] autorelease];
[task setLaunchPath: #"/usr/bin/file"];
[task setArguments: [NSArray arrayWithObjects: #"-b", #"--mime-type", path, nil]];
NSPipe *pipe = [NSPipe pipe];
[task setStandardOutput: pipe];
NSFileHandle *file = [pipe fileHandleForReading];
[task launch];
[task waitUntilExit];
if ([task terminationStatus] == YES) {
NSData *data = [file readDataToEndOfFile];
return [[[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding] autorelease];
} else {
return nil;
}
If you called that on a PDF file it would spit out: application/pdf
Based on the Lawrence Dol/slf answer above, I have solved the NSURL loading the entire file into memory issue by chopping the first few bytes into a head-stub and getting the MIMEType of that. I have not benchmarked it, but it's probably faster this way too.
+ (NSString*) mimeTypeForFileAtPath: (NSString *) path {
// NSURL will read the entire file and may exceed available memory if the file is large enough. Therefore, we will write the first fiew bytes of the file to a head-stub for NSURL to get the MIMEType from.
NSFileHandle *readFileHandle = [NSFileHandle fileHandleForReadingAtPath:path];
NSData *fileHead = [readFileHandle readDataOfLength:100]; // we probably only need 2 bytes. we'll get the first 100 instead.
NSString *tempPath = [NSHomeDirectory() stringByAppendingPathComponent: #"tmp/fileHead.tmp"];
[[NSFileManager defaultManager] removeItemAtPath:tempPath error:nil]; // delete any existing version of fileHead.tmp
if ([fileHead writeToFile:tempPath atomically:YES])
{
NSURL* fileUrl = [NSURL fileURLWithPath:path];
NSURLRequest* fileUrlRequest = [[NSURLRequest alloc] initWithURL:fileUrl cachePolicy:NSURLCacheStorageNotAllowed timeoutInterval:.1];
NSError* error = nil;
NSURLResponse* response = nil;
[NSURLConnection sendSynchronousRequest:fileUrlRequest returningResponse:&response error:&error];
[[NSFileManager defaultManager] removeItemAtPath:tempPath error:nil];
return [response MIMEType];
}
return nil;
}
On Mac OS X this would be handled through LaunchServices and UTIs. On the iPhone these are not available. Since the only way for data to get into your sandbox is for you to put it there, most apps have intrinsic knowledge about the data of any file they can read.
If you have a need for such a feature you should file a feature request with Apple.
I'm not sure what are the practices on iPhone, but if you're allowed to, I'd make use of UNIX philosophy here: use program file, which is the standard way to detect filetype on an UNIX operating system. It includes a vast database of magic markers for filetype detection. Since file is probably not shipped on iPhone, you could include it in your app bundle. There might be a library implementing file's functionality.
Alternatively, you could trust the browser. Browsers send the MIME type they guessed somewhere in the HTTP headers. I know that I can easily grab the MIME type information in PHP. That of course depends if you're willing to trust the client.
Make sure are you import the coreservices
import <CoreServices/CoreServices.h>
in your file.