check if a file exists objective-c - objective-c

I used the codes below to check if a file exists
bool b=[[NSFileManager defaultManager] fileExistsAtPath:filePath];
The codes worked on IOS.
But When I migrate it to mac os x,
But I found whether the file exists on disk with filePath,
b always returns 0, which means the file does not exists.
I wonder if there is difference between ios and macosx
Welcome any comment

From docs, I think you're using path with tilde
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSFileManager_Class/Reference/Reference.html#//apple_ref/occ/instm/NSFileManager/fileExistsAtPath:isDirectory:
path
The path of a file or directory. If path begins with a tilde (~), it must first be expanded with stringByExpandingTildeInPath, or this method will return NO.
tilde makes path relative to your home directory (such as /Users/username/)
you can find out by calling NSLog(#"%#",filePath); if filePath is of type NSString

Related

Filepath lastPathComponent from HFS or POSIX path

I am on OSX, not iOS, Objective-C
I receive external input like this and i need to get the file.
Case A (posix path): "path/to/afile.extension"
Case B (HFS path): "path:to:afile.extension"
In Case A i can get the file with
[path lastPathComponent];
In Case B i can get it via
[[path componentsSeparatedByString:#":"] lastObject];
Unfortunately i don't know if the input is of type A or B. What would be the best way to identify if the delivered path is a posix path or a HFS path?
What would be the best way to identify if the delivered path is a posix path or a HFS path?
Off-the-top-of-my-head: I don't think you can do this trivially based on the string as the POSIX path separator, '/', is a valid in a HFS file name, and vice-versa. E.g. the POSIX path fragment:
... Desktop/a:colon.txt
and the HFS path fragment:
... Desktop:a/colon.txt
refer to the same file.
What you could do instead is check if the path exists using file manager (NSFileManager) calls - these take HFS paths - and the access(2) system call - which takes a POSIX path. If only one of these works you know the type of path you have, if both work you've got some unusually named disks and files and the path is ambiguous! (And if neither work the path is invalid interpreted either way.)
You can also do checks by creating a file NSURL from the path and if successful then calling NSURL methods to check for existence.
Update
Your comment states that the files do not exist so checking for existence will obviously fail. So think about examining the path to work it out, only producing an error for ones you cannot figure out. E.g.:
If a path contains only '/' or ':' delimiters you can determine POSIX or HFS
A full HFS path always starts with the volume name followed by a colon. Determine the mounted volume names and check those against the path you have, if there is a match for one you have a HFS path
Etc.
For checking for characters in a string, volume names, etc. start with the NSString, NSFileManager and NSURL documentation. Once you've built up your series of tests if you have any problems etc. ask a new question describing your tests, showing your code, etc. and someone will undoubtedly help you.
HTH

Is there something im not understaning about the fileExistsAtPath:isDirectory method?

I do not understand how this method works. Here is the code
BOOL isDir = NULL;
BOOL returnVal;
path = #"/Users/me/Desktop/kkk";
returnVal = [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDir];
And here are the results if:
1) kkk is a file
returnVal = NO
isDir = NO
2) kkk is an empty directory
returnVal = YES
isDir = YES
Scenario #2 seems to work as expected, but according to the documentation:
path
The path of a file or directory. If path begins with a tilde (~), it must first be expanded with stringByExpandingTildeInPath, or this method will return NO.
isDirectory
Upon return, contains YES if path is a directory or if the final path element is a symbolic link that points to a directory, otherwise contains NO. If path doesn’t exist, this value is undefined upon return. Pass NULL if you do not need this information.
So for scenario #1 shouldnt the result be the following?
returnVal = YES
isDir = NO
1) Edit
For the comments below.
But the files do exist. I create the file manually to test it. lol. its only a program with 4 lines of code. I have both file/folder on the desktop. First i put a file there called "kkk" (with no extention) then i remove the file and place a folder there called "kkk". It works for the folder, but not for the file. Interestingly, if the file has an extension, it works. So is there something wrong with a file with no extension ? (are you guys still not able to reproduce it with no extention?)
2) EDIT
Thanks for helping me solve this guys. I have my Mac set to display the extension of files. But it seems Mac as an odd behavior. I select the file "kk.plist" and then rename the file to "kk" as you see in the image. As soon as i do this Mac OSx automatically selects the hide extension option. So when i thought the file was "kk", it was still "kk.plist" with its extension hidden. As you can see, both files have the same extension, one is hidden, the other is not. I didnt realize hidden extensions can be applied to one file only. Thanks.
1) kkk is a file
returnVal = NO
isDir = NO
⋮
So for scenario #1 shouldnt the result be the following?
returnVal = YES
isDir = NO
Yes. But be wary of the Finder hiding things from you when you're trying to verify results from this method.
As you found, one example is hiding extensions: you gave a path with no extension and were surprised when it didn't find a file that you thought had no extension; in truth, it still had an extension, which the Finder had hidden, so it still did not match the path, so the result you got was correct.
The other example is hidden (a.k.a. invisible) items. You may get a result of YES for a file that you can't find in the Finder. The Go command will temporarily reveal an invisible directory, but won't help you for files.
Whenever fileExists:isDirectory:'s results surprise you, and the Finder appears to show that the results are wrong, try to ls the path in the Terminal:
ls -dl /path/to/item
If that command prints a description of the item, then it exists. If it prints an error, then it doesn't. You can also tell from the output whether the item is a directory or not.

How do I tell if a file is contained in a directory?

What's the right way to tell if a file is contained within a given directory, or a subdirectory thereof?
I want something like:
if ([directoryPath contains: filePath]) {
// file is in directory, or in a subdirectory of directory.
}
Example:
ContainerPath: /Users/sfisher/Library/Application Support/iPhone Simulator/5.1/Applications/89A57CCB-250D-4D10-B913-EA456004B431/AppName.app
Not matching: /Users/sfisher/Library/Application Support/iPhone Simulator/5.1/Applications/89A57CCB-250D-4D10-B913-EA456004B431/Documents/db/Sample Data
Matching: /Users/sfisher/Library/Application Support/iPhone Simulator/5.1/Applications/89A57CCB-250D-4D10-B913-EA456004B431/AppName.app/Samples/1
I could convert everything to strings (including appending a "/" to the container directory) and check for a string match, but it seems there should be a built-in method for this.
In principle, your underlying desire is surprising impossible. A given file path may include through symbolic or hard links, making "containment" a very complicated question. These kinds of links are uncommon in iOS, but iOS is still Unix, and in Unix such things are legal.
So your real question is actually whether one path specifier (string) is contained in another. So checking the paths as strings is the correct approach.
I think a simple string match is the right way to do it:
if (![directoryPath hasSuffix:#"/"]) directoryPath = [directoryPath stringByAppendingString:#"/"];
if ([filePath hasPrefix:directoryPath]) {
// ...
}
Note that this doesn't deal with complications introduced by symlinks, or with relative paths.

Problems reading local text file with [NSString stringWithContentsOfFile...] with Objective-c returns null

This does not seem so complex. I just want to create a string object with the contents of a local text file called "test.txt" which I have placed in the root of my project.
I am trying to load it w/ the following code.
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"test" ofType:#"txt"];
NSString *textData = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
//The below works, but not my above... not sure why.
//textData = #"TEST TEST";
NSLog(#"Some text from a file of %#", textData);
NSLog(#"The length of the string is %lu", [textData length]);
The output from this code is
"Some text from a file of (null)"
"The length of the string is 0"
I am not sure why this is returning null instead of the contents of my text file. The encoding for the file seems appropriate. Also, the file exists. Am I dragging the file to the wrong location? Do I have to add it to my NSBundle mainBundle in some way?
Thanks!
If you actually fill in the error parameter in +stringWithContentsOfFile:encoding:error: then it would tell you why it's returning nil. You really ought to do that. The likely reason is there is no file at that path (or you don't have permissions to read it).
NSLog the filePath and see if it's nil. If the filePath is nil, I think you didn't put the file in right place. You should drag the file into the project navigator of your project in Xcode.
Also, double check the file name.
Log your filePath to see if it can actually find the file, if not, you probably add your test.txt in a wrong way. To add to main bundle, drag your test.txt into your xcode project, when prompted, just tick Copy items into destination group's folder (if needed) and select Create groups for any added folders.
All of the answers here helped a little bit. In particular the suggestion to fill in the error: in a way that does not return nil.
Eventually I found that I had to manually copy the .txt file I was trying to open to the same directory as the binary that was compiled. Just copying it into the xcode project did not seem to work for me.
I was having the exact same problem as you, Vincent. My understanding is that because I am making an console-based application, it doesn't compile and include files within a bundle in the same way that an iOS app would. Therefore, it's not including the file as expected. I was able to get it to work by typing out the full directory location of the file on my hard drive.
Drag and drop your test.txt file to Build Phases->copy bundle resources

fileExistsAtPath: (NSFileManager)

Is this method supposed to take a path as its argument?
It looks like it takes a filename as a path:
For example, /home/file.txt is a file, while /home/ is a path. This method looks like it takes the former as an argument.
Your distinction of "path" vs. "file" is not one that is common in Unix. Whether the final element of a path is a file or not doesn't affect the fact that it is a path. "/home/file.txt" looks like an absolute file path (though it could in fact be a deceptively named directory). "/home/" is an absolute directory path. Both are paths. (So is "foo/bar" — would you call that a "file" or a "path" in your terminology? Without inspecting the object at that path, we can't know whether it names a directory or a file.) Apple is using the term in its normal sense.
Yes, it takes a string that is a path - see the documentation:
Parameters
path
The path of a file or directory. If path begins with a tilde (~), it must first be expanded with stringByExpandingTildeInPath, or this method returns NO.
Note that /home/file.txt is a path, just like /home/. The former however is no directory, while the latter is.
If you're wanting to look for distinctions between files and folders, see -fileExistsAtPath:isDirectory:.
Usage:
BOOL isDirectory;
if ([self fileExistsAtPath:#"/Users/me/Subfolder" isDirectory:&isDirectory] && isDirectory)
{
// Exists and is a directory. Isn't that neat?
}