Retired Document
Important: This document is replaced by File System Programming Guide.
Working with the Contents of a Directory
This article describes two approaches to working with the contents of a directory. NSFileManager
provides several methods that return arrays of paths or URLs for items in a directory. To iterate over the the contents of a directory, you can use an NSDirectoryEnumerator
object.
Listing the Contents of a Directory
NSFileManager
provides a several methods that return the contents of a directory as an arrays of paths or (in Mac OS X v10.6 and later) URLs.
Contents as URLs
In Mac OS X v10.6 and later, you can obtain an array of NSURL
objects for each of the top-level items in a directory using contentsOfDirectoryAtURL:includingPropertiesForKeys:options:error:
. (This is the URL-based equivalent of contentsOfDirectoryAtPath:error:
. If you need to recurse into subdirectories, use enumeratorAtURL:includingPropertiesForKeys:options:errorHandler:
as shown in Using a Directory Enumerator). If you’re only interested in the URLs and no other attributes, then pass an empty array for the keys and 0
for the options, as shown in this example:
NSURL *url = <#A URL for a directory#>; |
NSError *error = nil; |
NSArray *array = [[NSFileManager defaultManager] |
contentsOfDirectoryAtURL:url |
includingPropertiesForKeys:[NSArray array] |
options:0 |
error:&error]; |
if (array == nil) { |
// Handle the error |
} |
One of the benefits of using URLs, however, is that you can also efficiently retrieve additional information about each item. If you want to have the property caches of the returned URLs pre-populated with a default set of attributes, then pass nil
for the keys and 0
for the options. You can also specify which attributes to retrieve and options to omit subdirectories, the contents of file packages, and hidden files, as illustrated in the following example:
NSURL *url = <#A URL for a directory#>; |
NSError *error = nil; |
NSArray *properties = [NSArray arrayWithObjects: NSURLLocalizedNameKey, |
NSURLCreationDateKey, NSURLLocalizedTypeDescriptionKey, nil]; |
NSArray *array = [[NSFileManager defaultManager] |
contentsOfDirectoryAtURL:url |
includingPropertiesForKeys:properties |
options:(NSDirectoryEnumerationSkipsPackageDescendants | |
NSDirectoryEnumerationSkipsHiddenFiles) |
error:&error]; |
if (array == nil) { |
// Handle the error |
} |
Contents as Path Strings
If you simply want a list of the contents of a directory, excluding any subdirectories (and without traversing symbolic links), you use contentsOfDirectoryAtPath:error:
, as shown in this example:
NSString *path = <#A path to a directory#>; |
NSError *error = nil; |
NSArray *array = [[NSFileManager defaultManager] |
contentsOfDirectoryAtPath:path error:&error]; |
if (array == nil) { |
// Handle the error |
} |
If you need a recursive listing—one that contains the filenames of the items in a given directory and all its subdirectories—you can use subpathsOfDirectoryAtPath:error:
, as shown in this example:
NSString *path = <#A path to a directory#>; |
NSError *error = nil; |
NSArray *array = [[NSFileManager defaultManager] |
subpathsOfDirectoryAtPath:path error:&error]; |
if (array == nil) { |
// Handle the error |
} |
Using a Directory Enumerator
You use an NSDirectoryEnumerator
object to enumerate the contents of a directory and any subdirectories that it contains. NSDirectoryEnumerator
is an abstract class, a cover for a private concrete subclass tailored to the file system’s directory structure. You cannot create an NSDirectoryEnumerator
object directly—you use NSFileManager
to retrieve a suitable instance.
You use the NSFileManager
method enumeratorAtPath:
to retrieve a directory enumerator that returns items as file path strings. In Mac OS X v10.6 and later, you can use a directory enumerator that returns items as URLs. (If you’re going to perform any operations with the returned items, it’s typically more efficient to use URLs.) You retrieve such an instance from a file manager object using enumeratorAtURL:includingPropertiesForKeys:options:errorHandler:
.
Both enumerators return the paths of all files and directories contained within that directory. The paths are relative to the directory. The enumeration is recursive, including the files of all subdirectories, and crosses device boundaries. It does not resolve symbolic links or attempt to traverse symbolic links that point to directories. Typically you simply enumerate the items in the NSDirectoryEnumerator
object. You can also, though, use the skipDescendents
method to avoid listing the contents of any directories you’re not interested in.
The following URL-based example (for Mac OS X v10.6 and later) illustrates how you can use enumeratorAtURL:includingPropertiesForKeys:options:errorHandler:
to list all the user-visible subdirectories of a given directory, noting whether they are directories or file packages. The keys array argument specifies that for each URL produced by this enumeration the specified property values are pre-fetched and cached—this makes subsequent access more efficient. The options argument specifies that enumeration should not list the contents of file packages and hidden files. The error handler is a block object that returns a Boolean value; if it returns YES
, the enumeration continues after the error; if it returns NO
, the enumeration stops.
NSURL *directoryURL = <#An NSURL object that contains a reference to a directory#>; |
NSArray *keys = [NSArray arrayWithObjects: |
NSURLIsDirectoryKey, NSURLIsPackageKey, NSURLLocalizedNameKey, nil]; |
NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] |
enumeratorAtURL:directoryURL |
includingPropertiesForKeys:keys |
options:(NSDirectoryEnumerationSkipsPackageDescendants | |
NSDirectoryEnumerationSkipsHiddenFiles) |
errorHandler:^(NSURL *url, NSError *error) { |
// Handle the error. |
// Return YES if the enumeration should continue after the error. |
return <#YES or NO#>; |
}]; |
for (NSURL *url in enumerator) { |
// Error-checking is omitted for clarity. |
NSNumber *isDirectory = nil; |
[url getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:NULL]; |
if ([isDirectory boolValue]) { |
NSString *localizedName = nil; |
[url getResourceValue:&localizedName forKey:NSURLLocalizedNameKey error:NULL]; |
NSNumber *isPackage = nil; |
[url getResourceValue:&isPackage forKey:NSURLIsPackageKey error:NULL]; |
if ([isPackage boolValue]) { |
NSLog(@"Package at %@", localizedName); |
} |
else { |
NSLog(@"Directory at %@", localizedName); |
} |
} |
} |
You can use other methods declared by NSDirectoryEnumerator
to determine attributes of files during the enumeration—both of the parent directory and the current file or directory—and to control recursion into subdirectories. The following string-based example enumerates the contents of a directory and lists files that have been modified within the last 24 hours; if, however, it comes across RTFD file packages, it skips recursion into them:
NSString *directoryPath = <#Get a path to a directory#>; |
NSDirectoryEnumerator *directoryEnumerator = [[NSFileManager defaultManager] enumeratorAtPath:directoryPath]; |
NSDate *yesterday = [NSDate dateWithTimeIntervalSinceNow:(-60*60*24)]; |
for (NSString *path in directoryEnumerator) { |
if ([[path pathExtension] isEqualToString:@"rtfd"]) { |
// Don't enumerate this directory. |
[directoryEnumerator skipDescendents]; |
} |
else { |
NSDictionary *attributes = [directoryEnumerator fileAttributes]; |
NSDate *lastModificationDate = [attributes objectForKey:NSFileModificationDate]; |
if ([yesterday earlierDate:lastModificationDate] == yesterday) { |
NSLog(@"%@ was modified within the last 24 hours", path); |
} |
} |
} |
Copyright © 1997, 2011 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2011-05-25