Accessing Files and Directories(

2018-10-29  本文已影响5人  ngugg

相关链接:
https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/AccessingFilesandDirectories/AccessingFilesandDirectories.html#//apple_ref/doc/uid/TP40010672-CH3-SW1

Before you can open a file, you first have to locate it in the file system. The system frameworks provide many routines for obtaining references to many well-known directories, such as the Library directory and its contents. You can also specify locations manually by building a URL or string-based path from known directory names.

When you know the location of a file, you can then start planning the best way to access it. Depending on the type of file, you may have several options. For known file types, you typically use built-in system routines to read or write the file contents and give you an object that you can use. For custom file types, you may need to read the raw file data yourself.

Choose the Right Way to Access Files

Table 2-1 File types with specialized routines

  1. File Type: Resource files
    Examples : Nib files,* Image files*, Sound files, Strings files, Localized resources
    Description: Apps use resource files to store data that is independent of the code that uses it. Resource files are commonly used to store localizable content such as strings and images. The process for reading data from a resource file depends on the resource type.

For information about how to read the contents of resource files, see Resource Programming Guide.

  1. File Type: Text files
    Examples : Plain text file,UTF-8 formatted file,UTF-16 formatted file
    Description: A text file is an unstructured sequence of ASCII or Unicode characters. You typically load the contents of a text file into an NSString object but may also read and write a text file as a raw stream of characters.

For information about using the NSString class to load text from a file, see String Programming Guide.

  1. File Type: Structured data files
    Examples : XML file,Property list file,Preference file
    Description: A structured data file usually consists of string-based data arranged using a set of special characters.

For information about parsing XML, see Event-Driven XML Programming Guide.

  1. File Type: Archive files
    Examples : Binary files created using a keyed archiver object
    Description: An archive is a file format used to store a persistent version of your app’s runtime objects. An archiver object encodes the state of the objects into a stream of bytes that can be written to disk all at once. An unarchiver reverses the process, using the stream of bytes to re-create the objects and restore them to their previous state.

Archives are often a convenient alternative to implementing custom binary file formats for your documents or other data files.

For information on how to create and read archive files, see Archives and Serializations Programming Guide.

  1. File Type: File packages
    Examples : Custom document formats
    Description: A file package is a directory that contains any number of custom data files but which is presented to the user as if it were a single file. Apps can use file packages to implement complex file formats that contain multiple distinct files, or a mixture of different types of files. For example, you might use a file package if your file format includes both a binary data file and one or more image, video, or audio files. You access the contents of a file package using NSFileWrapper objects, as described in Using FileWrappers as File Containers.
  1. File Type: Bundles
    Examples : Apps,Plug-ins, Frameworks
    Description: Bundles provide a structured environment for storing code and the resources used by that code. Most of the time, you do not work with the bundle itself but with its contents. However, you can locate bundles and obtain information about them as needed.

For information about bundles and how you access them, see Bundle Programming Guide

  1. File Type: Code files
    Examples : Binary code resources, Dynamic shared libraries
    Description: Apps that work with plug-ins and shared libraries need to be able to load the associated code for that item to take advantage of its functionality.

For information about how to load code resources into memory, see Code Loading Programming Topics.

In situations where the standard file formats are insufficient, you can always create your own custom file formats. When reading and writing the content of custom files, you read and write data as a stream of bytes and apply those bytes to your app’s file-related data structures. You have complete control over how you read and write the bytes and how you manage your file-related data structures. For more information about the techniques for reading and writing files that use custom file formats, see Techniques for Reading and Writing Files Without File Coordinators.

Specifying the Path to a File or Directory

The preferred way to specify the location of a file or directory is to use the [NSURL](https://developer.apple.com/documentation/foundation/nsurl) class. Although the [NSString](https://developer.apple.com/library/archive/documentation/LegacyTechnologies/WebObjects/WebObjects_3.5/Reference/Frameworks/ObjC/Foundation/Classes/NSStringClassCluster/Description.html#//apple_ref/occ/cl/NSString) class has many methods related to path creation, URLs offer a more robust way to locate files and directories. For apps that also work with network resources, URLs also mean that you can use one type of object to manage items located on a local file system or on a network server.

Note: In addition to NSURL, you can also use the CFURLRef opaque type to manipulate paths as URLs. The NSURL class is toll-free bridged with the CFURLReftype, which means you can use them interchangeably in your code. For more information about how to create and manipulate URLs using Core Foundation, see CFURL Reference.

For most URLs, you build the URL by concatenating directory and file names together using the appropriate NSURL methods until you have the path to the item. A URL built in that way is referred to as a path-based URL because it stores the names needed to traverse the directory hierarchy to locate the item. (You also build string-based paths by concatenating directory and file-names together, with the results stored in a slightly different format than that used by the NSURL class.) In addition to path-based URLs, you can also create a file reference URL, which identifies the location of the file or directory using a unique ID.

All of the following entries are valid references to a file called MyFile.txt in a user’s Documents directory:

Path-based URL: file://localhost/Users/steve/Documents/MyFile.txt

File reference URL: file:///.file/id=6571367.2773272/

String-based path: /Users/steve/Documents/MyFile.txt

You create URL objects using the NSURL methods and convert them to file reference URLs only when needed. Path-based URLs are easier to manipulate, easier to debug, and are generally preferred by classes such as NSFileManager. An advantage of file reference URLs is that they are less fragile than path-based URLs while your app is running. If the user moves a file in the Finder, any path-based URLs that refer to the file immediately become invalid and must be updated to the new path. However, as long as the file moved to another location on the same disk, its unique ID does not change and any file reference URLs remain valid.

Important: Although they are safe to use while your app is running, file reference URLs are not safe to store and reuse between launches of your app because a file’s ID may change if the system is rebooted. If you want to store the location of a file persistently between launches of your app, create a bookmark as described in Locating Files Using Bookmarks.

Of course, there are still times when you might need to use strings to refer to a file. Fortunately, the NSURL class provides methods to convert path-based URLs to and from NSString objects. You might use a string-based path when presenting that path to the user or when calling a system routine that accepts strings instead of URLs. The conversion between NSURL objects and NSString objects is done using the NSURL class’s method absoluteString.

Because NSURL and NSString describe only the location of a file or directory, you can create them before the actual file or directory exists. Neither class attempts to validate the actual existence of the file or directory you specify. In fact, you must create the path to a nonexistent file or directory before you can create it on disk.

If you have an NSURL object that refers to an actual file or directory on disk, and you want to get the user visible name of the volume on which it resides, you use the method getResourceValue:forKey:error: in a two step process:
如果您有一个NSURL对象引用磁盘上的实际文件或目录,并且您希望获取其所在卷的用户可见名称,则使用方法getResourceValue:forKey:error:分两步执行:

Use the NSURLLocalizedNameKey constant rather than the NSURLNameKey constant. Using NSURLNameKey returns the name of the volume in the file system, which may not be the same as the user visible name. Listing 2-1 demonstrates this process for the current user’s home directory.

Listing 2-1 Obtaining the user visible volume name for a resource URL

NSURL *url = [NSURL fileURLWithPath:NSHomeDirectory()];
NSURL *volumeURL = nil;
NSString *volumeName = nil;
if ([url getResourceValue:&volumeURL forKey:NSURLVolumeURLKey error:nil]) {
    if ([volumeURL getResourceValue:&volumeName forKey:NSURLLocalizedNameKey error:nil]) {
        NSLog(@"The volume name is: %@", volumeName);
    }
}

For more information about the methods you use to create and manipulate URLs and strings, see NSURL Class Reference and NSString Class Reference.

Locating Items in the File System

Before you can access a file or directory, you need to know its location. There are several ways to locate files and directories:

The file systems of iOS and macOS impose specific guidelines on where you should place files, so most of the items your app creates or uses should be stored in a well-known place. Both systems provide interfaces for locating items in such well-known places, and your app can use these interfaces to locate items and build paths to specific files. An app should prompt the user to specify the location of a file or directory only in a limited number of situations that are described in Using the Open and Save Panels.

Asking the User to Locate an Item 要求用户找到一个项目

In macOS, user interactions with the file system should always be through the standard Open and Save panels. Because these panels involve interrupting the user, use them only in a limited number of situations:

Never use the Open and Save panels to access any files that your app created and uses internally. Support files, caches, and app-generated data files should be placed in one of the standard directories dedicated to app-specific files.

For information on how to present and customize the Open and Save panels, see Using the Open and Save Panels.

Locating Items in Your App Bundle

Apps that need to locate resource files inside their bundle directory (or inside another known bundle) must do so using an NSBundle object. Bundles eliminate the need for your app to remember the location of individual files by organizing those files in a specific way. The methods of the NSBundle class understand that organization and use it to locate your app’s resources on demand. The advantage of this technique is that you can generally rearrange the contents of your bundle without rewriting the code you use to access it. Bundles also take advantage of the current user’s language settings to locate an appropriately localized version of a resource file.

The following code shows how to retrieve a URL object for an image named MyImage.png that is located in the app’s main bundle. This code determines only the location of the file; it does not open the file. You would pass the returned URL to a method of the NSImage class to load the image from disk so that you could use it.

NSURL* url = [[NSBundle mainBundle] URLForResource:@"MyImage" withExtension:@"png"];

For more information about bundles, including how to locate items in a bundle, see Bundle Programming Guide. For specific information about loading and using resources in your app, see Resource Programming Guide.

Locating Items in the Standard Directories

When you need to locate a file in one of the standard directories, use the system frameworks to locate the directory first and then use the resulting URL to build a path to the file. The Foundation framework includes several options for locating the standard system directories. By using these methods, the paths will be correct whether your app is sandboxed or not:
当您需要在其中一个标准目录中找到文件时,请使用系统框架首先找到该目录,然后使用生成的URL构建该文件的路径。 Foundation框架包括几个用于查找标准系统目录的选项。 通过使用这些方法,无论您的应用是否为沙盒,路径都是正确的:

You can use the URL or path-based string you receive from the preceding routines to build new objects with the locations of the files you want. Both the NSURL and NSString classes provide path-related methods for adding and removing path components and making changes to the path in general. Listing 2-2 shows an example that searches for the standard Application Support directory and creates a new URL for a directory containing the app’s data files.

Listing 2-2 Creating a URL for an item in the app support directory

- (NSURL*)applicationDataDirectory {
    NSFileManager* sharedFM = [NSFileManager defaultManager];
    NSArray* possibleURLs = [sharedFM URLsForDirectory:NSApplicationSupportDirectory
                                 inDomains:NSUserDomainMask];
    NSURL* appSupportDir = nil;
    NSURL* appDirectory = nil;

    if ([possibleURLs count] >= 1) {
        // Use the first directory (if multiple are returned)
        appSupportDir = [possibleURLs objectAtIndex:0];
    }

    // If a valid app support directory exists, add the
    // app's bundle ID to it to specify the final directory.
    if (appSupportDir) {
        NSString* appBundleID = [[NSBundle mainBundle] bundleIdentifier];
        appDirectory = [appSupportDir URLByAppendingPathComponent:appBundleID];
    }
    return appDirectory;
}

Locating Files Using Bookmarks

If you want to save the location of a file persistently, use the bookmark capabilities of NSURL. A bookmark is an opaque data structure, enclosed in an NSDataobject, that describes the location of a file. Whereas path- and file reference URLs are potentially fragile between launches of your app, a bookmark can usually be used to re-create a URL to a file even in cases where the file was moved or renamed.

To create a bookmark for an existing URL, use the bookmarkDataWithOptions:includingResourceValuesForKeys:relativeToURL:error: method of NSURL. Specifying the NSURLBookmarkCreationSuitableForBookmarkFile option creates an NSData object suitable for saving to disk. Listing 2-3 shows a simple example implementation that uses this method to create a bookmark data object.

Listing 2-3 Converting a URL to a persistent form

- (NSData*)bookmarkForURL:(NSURL*)url {
    NSError* theError = nil;
    NSData* bookmark = [url bookmarkDataWithOptions:NSURLBookmarkCreationSuitableForBookmarkFile
                                            includingResourceValuesForKeys:nil
                                            relativeToURL:nil
                                            error:&theError];
    if (theError || (bookmark == nil)) {
        // Handle any errors.
        return nil;
    }
    return bookmark;
}

If you write the persistent bookmark data to disk using the writeBookmarkData:toURL:options:error: method of NSURL, what the system creates on disk is an alias file. Aliases are similar to symbolic links but are implemented differently. Normally, users create aliases from the Finder when they want to create links to files elsewhere on the system.

To transform a bookmark data object back into a URL, use the URLByResolvingBookmarkData:options:relativeToURL:bookmarkDataIsStale:error: method of NSURL. Listing 2-4 shows the process for converting a bookmark back into a URL.

Listing 2-4 Returning a persistent bookmark to its URL form

- (NSURL*)urlForBookmark:(NSData*)bookmark {
    BOOL bookmarkIsStale = NO;
    NSError* theError = nil;
    NSURL* bookmarkURL = [NSURL URLByResolvingBookmarkData:bookmark
                                            options:NSURLBookmarkResolutionWithoutUI
                                            relativeToURL:nil
                                            bookmarkDataIsStale:&bookmarkIsStale
                                            error:&theError];
 
    if (bookmarkIsStale || (theError != nil)) {
        // Handle any errors
        return nil;
    }
    return bookmarkURL;
}

The Core Foundation framework provides a set of C-based functions that parallel the bookmark interface provided by NSURL. For more information about using those functions, see CFURL Reference.

上一篇 下一篇

猜你喜欢

热点阅读