I am donwloading and retrieving files with ASIHTTPRequest. It already works, but now I am trying to break the download, when it is already stored. I can't figure out, how to implement this problem. I would like to solve it with an if-clause: if the file is not cached, download it else break. Would you mind to help me writing a proper Objective-C code? I have the file path, if I need it so compare or look after that file.
Thanks in advance!
pseudo code :
-(IBAction) download : (id) sender {
if (data1.pdf) {
// the download algorithm
}
else
break;
}
If you mean how you can check if a file is stored in the documents directory of your device, then you can use:
NSString* documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString* file = [documentsPath stringByAppendingPathComponent:#"data.pdf"];
if ([[NSFileManager defaultManager] fileExistsAtPath:file]) {
...
Related
I am saving video/image in document directory.Now once the image is saved in document directory I want to save its reference in my local database.So I am thinking I can save URL of the image in the local database.
So is it constant throughout my app?
It's not constant, i have observed every time you launch the app it'll be different, but your data is moved to this new path. You can save your file name in your database, and dynamically append this file name to NSDocument directory.
- (NSString *)documentsFilePath:(NSString *)fileName {
NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsDir = [dirPaths firstObject];
NSString *filePath = [docsDir stringByAppendingPathComponent:fileName];
return filePath;
}
- (void)storeFile:(NSString *)fileName {
NSString *filePath = [self documentsFilePath:fileName];
// create if needed
if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
// Write your data to file system here...
}
}
- (void)deleteFile:(NSString *)fileName {
NSString *filePath = [self documentsFilePath:fileName];
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
NSError *deleteErr = nil;
[[NSFileManager defaultManager] removeItemAtPath:filePath error:&deleteErr];
if (deleteErr) {
NSLog(#"Can't delete %#: %#", filePath, deleteErr);
}
}
}
Please handle nil checks and store only filename in DB
No, it's not constant. Whenever your app reinstall or updated on device the document directory will change, because when app installed on device os made an directory for app with some random id and each install this random it get changed by OS.
So, you need to make it dynamic own your own, like store the file name only and append the document directory path while using it.
I would suggest only saving the filename or subdirectory/filename (if you have a subdirectory) in the database and then only attaching that to the NSDocumentDirectory.
This will ensure that you always know where the file is...
NSDocumentDirectory is however consistent accross updates, so the files should remain in the document directory even if you update...
I just make a file browser for iOS, I just need to know how to open any kind of file in a UIWebview. I think the webview can open any kind of file, that's because I chose to use a UIWebView to view the files directly in the app. Now my question.
How to programmatically switch to a UIViewController in the same UIStoryBoard and display the file? The file URL is stored in a string called path.
This is how fare I am, I just need to add the file viewer.
Can someone help me?
-(void) displayFile:(NSString*)fileName
{
NSError *error = nil;
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
TO get the filename
NSString *folderPath = [documentsDirectory stringByAppendingPathComponent:fileName];
if (![[NSFileManager defaultManager] fileExistsAtPath:folderPath]) //Optionally check if folder already hasn't existed.
{
// do something
}
}
Hope this helps you...
A little embarrassing question, but I can find an answer which works in my case... I need to put some xml file (settings.xml) in order to read some data from it during application runtime.
According to some answers here and not only here, I have putted it here:
~/Library/Application Support/iPhone Simulator/5.0/[AppUUID]/Documents
and I'm trying to use it as follows:
// Loading data from external XML File
NSURL *url = [[NSBundle mainBundle]
URLForResource: #"settings" withExtension:#"xml"];
NSError *err;
if ([url checkResourceIsReachableAndReturnError:&err] == NO){
NSLog(#"FILE NOT FOUND");
}
Result: "FILE NOT FOUND".
I've tried to do put the file under any possible directory in
~/Library/Application Support/iPhone Simulator/5.0/[AppUUID]/ and efect is still the same.
I'm using XCode 4.2
If you are putting the file into the .../Documents folder then you need to use the following code to access it (you are looking for it in the App Bundle, which is a different location altogether):
NSString *docFolder = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filename = [docFolder stringByAppendingPathComponent:#"settings.xml"];
if ([[NSFileManager defaultManager] fileExistsAtPath:filename])
{
// Read file
}
else
{
NSLog(#"settings.xml file not found!");
}
In my game, I'm saving stats of the player in a plist that I store in the Documents directory. I have an empty dictionary of each stats that should be saved named "Default_Stats.plist" so that if it's the first time the app is loaded, it will copy it in the appropriate directory so it could be loaded and overwritten at will. The problem is, every time my app is loaded, it doesn't recognize the "Stats.plist" and overwrite it with the Default Stats, resetting every stats the player have made... And weird enough, it was perfectly working on the simulator, but not on the device. Here's my code :
In this method I read the stats :
- (void) readStatsFromFile{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *statsPath = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"Stats.plist"];
//Check if the file has already been created
if (![[NSFileManager defaultManager] fileExistsAtPath:statsPath]){
[self createStatsList];
}else{
stats = [[NSMutableDictionary dictionaryWithContentsOfFile:statsPath]retain];
}
}
Here's my creating method :
- (void) createStatsList{
NSString *statsPath = [[NSBundle mainBundle] bundlePath];
statsPath = [statsPath stringByAppendingPathComponent:#"Default_Stats.plist"];
stats = [[NSMutableDictionary dictionaryWithContentsOfFile:statsPath] retain];
[self writeStatsToFile];
}
And my writing method :
- (void) writeStatsToFile{
BOOL ok;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *statsPath = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"Stats.plist"];
ok = [stats writeToFile:statsPath atomically:YES];
if (!ok) {
NSLog(#"Couldn't write to file");
}else
NSLog(#"Stats written succesfully!");
}
Please help, I really don't understand what's wrong! I hope I've made myself clear enough!
Use filepath instead of absolute path.
Maybe duplicates exist in your mac, which makes exists=true on simulator, but not on device.
The easiest way to check would be to NSLog the paths encountered. Refer to these tools - they allow console logs to be captured for release builds running on your device.
Most likely that your documents directory just doesn't exist - on the simulator you share a documents directory with everyone on the Mac; on the device everyone has his own directory. Use the file manager method
createDirectoryAtURL:url withIntermediateDirectories:YES
to make sure that the directory is there before you try writing there. (I tend to use the URL methods instead of the file path methods).
PS. I'd recommend having one method that returns the path or url that you want. It's a good habit not to duplicate your code again and again.
I would do pretty much that, like everything in one session:
gets the URL for the file in the Document folder;
if the file is not there yet, copies the file from bundle to the Documents folder;
that should be the method for that, I have defined some macros for avoiding mistyping the file's name in the code:
- (NSURL *)statsFileURL {
#define NSStringFromFileNameWithExtension(filename, extension) [(filename) stringByAppendingPathExtension:(extension)]
#define kExtension #"plist"
#define kDefaultStatsFileName #"Default_Stats"
#define kCustomStatsFileName #"Stats"
NSURL *_returnURL = nil;
NSFileManager *_fileManager = [NSFileManager defaultManager];
NSURL *_documentDirectory = [[_fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
NSURL *_myFileURLInDocumentFolder = [_documentDirectory URLByAppendingPathComponent:NSStringFromFileNameWithExtension(kDefaultStatsFileName, kExtension)];
if ([_fileManager fileExistsAtPath:[_myFileURLInDocumentFolder path]]) {
_returnURL = _myFileURLInDocumentFolder;
} else {
NSURL *_myFileURLInBundle = [[NSBundle mainBundle] URLForResource:kDefaultStatsFileName withExtension:kExtension];
if ([_fileManager fileExistsAtPath:[_myFileURLInBundle path]]) {
NSError *_error = nil;
if ([_fileManager copyItemAtURL:_myFileURLInBundle toURL:_myFileURLInDocumentFolder error:&_error]) {
if (_error == nil) {
_returnURL = _myFileURLInDocumentFolder;
} else {
// some error during copying
}
} else {
// some error during copying
}
} else {
// the file does not esixts at all, not even in the bundle
}
}
return _returnURL;
}
the URL always points inside the Documents folder, so you will have read/write access to the file – or will be nil if some error happens.
after you have the URL, you can restore back to file without any issue, and at some other point in runtime you can override the file for your convenience anytime.
NOTE: you may need to extend this code for a more detailed error handling, I put the comment only the places when you need to worry about potential errors.
I have an application with In-App Purchase, that when the user buy something, download one html file into the Documents folder of my app.
Now I must check if this HTML file exists, so if true, load this HTML file, else load my default html page.
How I can do that? With NSFileManager I can't get outside of mainBundle..
Swift 3:
let documentsURL = try! FileManager().url(for: .documentDirectory,
in: .userDomainMask,
appropriateFor: nil,
create: true)
... gives you a file URL of the documents directory. The following checks if there's a file named foo.html:
let fooURL = documentsURL.appendingPathComponent("foo.html")
let fileExists = FileManager().fileExists(atPath: fooURL.path)
Objective-C:
NSString* documentsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString* foofile = [documentsPath stringByAppendingPathComponent:#"foo.html"];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:foofile];
Apple recommends against relying on the fileExistAtPath: method. It's often better to just try to open a file and deal with the error if the file does not exist.
NSFileManager Class Reference
Note: Attempting to predicate behavior based on the current state of the file system or a particular file on the file system is not recommended. Doing so can cause odd behavior or race conditions. It's far better to attempt an operation (such as loading a file or creating a directory), check for errors, and handle those errors gracefully than it is to try to figure out ahead of time whether the operation will succeed. For more information on file system race conditions, see “Race Conditions and Secure File Operations” in Secure Coding Guide.
Source: Apple Developer API Reference
From the secure coding guide.
To prevent this, programs often check to make sure a temporary file with a specific name does not already exist in the target directory. If such a file exists, the application deletes it or chooses a new name for the temporary file to avoid conflict. If the file does not exist, the application opens the file for writing, because the system routine that opens a file for writing automatically creates a new file if none exists.
An attacker, by continuously running a program that creates a new temporary file with the appropriate name, can (with a little persistence and some luck) create the file in the gap between when the application checked to make sure the temporary file didn’t exist and when it opens it for writing. The application then opens the attacker’s file and writes to it (remember, the system routine opens an existing file if there is one, and creates a new file only if there is no existing file).
The attacker’s file might have different access permissions than the application’s temporary file, so the attacker can then read the contents. Alternatively, the attacker might have the file already open. The attacker could replace the file with a hard link or symbolic link to some other file (either one owned by the attacker or an existing system file). For example, the attacker could replace the file with a symbolic link to the system password file, so that after the attack, the system passwords have been corrupted to the point that no one, including the system administrator, can log in.
If you set up your file system differently or looking for a different way of setting up a file system and then checking if a file exists in the documents folder heres an another example. also show dynamic checking
for (int i = 0; i < numberHere; ++i){
NSFileManager* fileMgr = [NSFileManager defaultManager];
NSString *documentsDirectory = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents"];
NSString* imageName = [NSString stringWithFormat:#"image-%#.png", i];
NSString* currentFile = [documentsDirectory stringByAppendingPathComponent:imageName];
BOOL fileExists = [fileMgr fileExistsAtPath:currentFile];
if (fileExists == NO){
cout << "DOESNT Exist!" << endl;
} else {
cout << "DOES Exist!" << endl;
}
}
Swift 2.0
This is how to check if the file exists using Swift
func isFileExistsInDirectory() -> Bool {
let paths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
let documentsDirectory: AnyObject = paths[0]
let dataPath = documentsDirectory.stringByAppendingPathComponent("/YourFileName")
return NSFileManager.defaultManager().fileExistsAtPath(dataPath)
}
check if file exist in side the document/catchimage path :
NSString *stringPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0];
NSString *tempName = [NSString stringWithFormat:#"%#/catchimage/%#.png",stringPath,#"file name"];
NSLog(#"%#",temName);
if([[NSFileManager defaultManager] fileExistsAtPath:temName]){
// ur code here
} else {
// ur code here**
}
NSArray *directoryPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString *imagePath = [directoryPath objectAtIndex:0];
//If you have superate folder
imagePath= [imagePath stringByAppendingPathComponent:#"ImagesFolder"];//Get docs dir path with folder name
_imageName = [_imageName stringByAppendingString:#".jpg"];//Assign image name
imagePath= [imagePath stringByAppendingPathComponent:_imageName];
NSLog(#"%#", imagePath);
//Method 1:
BOOL file = [[NSFileManager defaultManager] fileExistsAtPath: imagePath];
if (file == NO){
NSLog("File not exist");
} else {
NSLog("File exist");
}
//Method 2:
NSData *data = [NSData dataWithContentsOfFile:imagePath];
UIImage *image = [UIImage imageWithData:data];
if (!(image == nil)) {//Check image exist or not
cell.photoImageView.image = image;//Display image
}
NSURL.h provided - (BOOL)checkResourceIsReachableAndReturnError:(NSError **)error to do so
NSURL *fileURL = [NSURL fileURLWithPath:NSHomeDirectory()];
NSError * __autoreleasing error = nil;
if ([fileURL checkResourceIsReachableAndReturnError:&error]) {
NSLog(#"%# exists", fileURL);
} else {
NSLog(#"%# existence checking error: %#", fileURL, error);
}
Or using Swift
if let url = URL(fileURLWithPath: NSHomeDirectory()) {
do {
let result = try url.checkResourceIsReachable()
} catch {
print(error)
}
}