Чтение онлайн

ЖАНРЫ

Программирование на Objective-C 2.0
Шрифт:

Возможно, вам потребуется также функция Foundation NSSearchPathForDPrectorieslnDomains для обнаружения в системе специальных папок, таких как Application. Копирование файлов и использование класса NSProcessInfo

В программе 16.6 показано средство командной строки для реализации простой операции копирования файлов. Эта команда применяется следующим образом. copy from-file {bcfjlysq afqk) to-file (afqk-rjgbz)

В отличие от метода NSFileManager copyPath:toPath:handler:, это средство ко-мандной строки позволяет также использовать to-file как имя папки. Тогда эта папка копируется в папку to-file под именем from-file. Еще одно отличие от ука-занного метода: если to-file уже существует, его содержимое перезаписывается. Это в большей степени согласуется со стандартной командой копирования UNIX (ср).

Для получения имен файлов из командной строки можно использовать ар-гументы argc и argv, передаваемые в main. В качестве этих аргументов в команд-ной строке указываются, соответственно, целый ряд типов аргументов (включая имя команды) и указатель на массив символьных С-строк.

Вместо обработки С-строк, что

приходится делать при работе с argv, исполь-зуйте класс Foundation NSProcessinfo. NSProcessInfo содержит методы, позволяющие задавать и считывать различные типы информации о выполняемом приложении (то есть вашем процессе). Эти методы приводятся в таблице 16.5.

Табл. 16.5. Методы класса NSProcessinfo Метод Описание +(NSProcessInfo *) processlnfo Возвращает информацию о текущем процессе. -(NSArray *) arguments Возвращает аргументы для текущего процесса в виде массива объектов NSString. -(NSDictionary *) environment Возвращает словарь, состоящий из пар «переменная/значение», представляющих текущие переменные среды (например, PATH и НОМЕ) вместе с их значениями. -(int) processldentifier Возвращает идентификатор процесса, то есть уникальный номер, назначаемый операционной системой для идентификации каждого выполняемого процесса. -(NSString *) processName Возвращает имя текущего выполняемого процесса. -(NSString *) globallyllniqueString Возвращает при каждом вызове новую уникальную строку. Это можно использовать для генерации уникальных имен временных файлов (см. упражнение 5). -(NSString *) hostName Возвращает имя хост-системы (возвращает SteveKochans-Computer.local в моей системе Mac OS X). -(NSUInteger) operatingSystem Возвращает число, обозначающее операционную систему (возвращает значение 5 на моем Маке). -(NSString *) operatingSystemName Возвращает имя операционной системы (возвращает константу NSMACHOperatingSystem на моем Маке, где возможные возвращаемые значения определены в NSProcessInfo.h). -(NSString *) operatingSystemVersionString Возвращает текущую версию операционной системы (возвращает Version 10.5.4 (Build 9Е17) в моей системе Mac OS X). -(void) setProcessName: (NSString *) name Задает имя name для текущего процесса. Следует использовать с осторожностью, поскольку необходимо учитывать некоторые предположения об имени вашего процесса (например, в настройках пользователя по умолчанию). // Реализация простой утилиты копирования #import <Foundation/NSString.h> #import <Foundation/NSArray.h> #import <Foundation/NSFileManager.h> #import <Foundation/NSAutoreleasePool.h> #import <Foundation/NSPathUtilities.h> #import <Foundation/NSProcesslnfo.h> int main {int argc, char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; NSFileManager *fm; NSString *source, *dest; BOOL isDir; NSProcessInfo *proc = [NSProcessInfo processlnfo]; NSArray *args = [proc arguments]; fm = [NSFileManager defaultManager]; // Проверка того, что в командной строке заданы два аргумента if ([args count] != 3) { NSLog (@"Usage: %@ src dest", [proc processName]); return 1; } source = [args objectAtlndex: 1]; dest = [args objectAtlndex: 2]; // Проверка того, что исходный файл можно читать if ([fm isReadableFileAtPath: source] == NO) { NSLog (@"Can't read %@", source); return 2; } // Является ли целевой файл (dest) папкой? // Если да, то исходный файл (source) добавляется в конец целевого пути ffm fileExistsAtPath: dest isDirectory: &isDir); if (isDir == YES) dest = [dest stringByAppendingPathComponent: [source lastPathComponent]]; // Удаление целевого файла, если он уже существует [fm removeFileAtPath: dest handler: nil]; // Все сделано, можно выполнять копирование if ([fm copyPath: source toPath: dest handler: nil] == NO) { NSLog (@"Copy failed!"); return 3; } NSLog (@"Copy of %@ to %@ succeeded!", source, dest); [pool drain]; return 0; }

Вывод программы 16.6 $ Is -I смотрим, какие файлы у нас есть total 96 -rwxr-xr-x 1 stevekoc staff 19956 Jul 24 14:33 copy -rw-r~r~1 stevekoc staff 1484 Jul 24 14:32 copy.m -rw-r-r- 1 stevekoc staff 1403 Jul 24 13:00 filel.m drwxr-xr-x 2 stevekoc staff 68 Jul 24 14:40 newdir -ПАГ-Г-Г--1 stevekoc staff 1567 Jul 24 14:12 pathl.m -rw-r-r--1 stevekoc staff 84 Jul 24 13:22 testfile $ copy попытка команды без аргументов Usage: copy src dest (Использование: ...) $ copy foo copy2 Can’t read foo (Невозможно прочитать foo) $ copy copy.m backup.m Copy of copy.m to backup.m succeeded! (Копирование copy.m в backup.m выполнено!) $ diff copy.m backup.m сравнение файлов $ copy copy.m newdir попытка копирования в папку Copy of copy.m to newdir/copy.m succeeeded! (Копирование copy.m в newdir/copy.m выполнено!) $ Is -I newdir total 8 -rw-r-r- 1 stevekoc staff 1484 Jul 24 14:44 copy.m $

Метод NSProcessInfo arguments возвращает массив строковых объектов. Первый элемент этого массива — имя процесса, остальные элементы содержат аргументы, которые вводятся в командной строке.

Сначала проверяем, что в командной строке введено два ар^менга. Для этого проверяем размер массива args, возвращаемого методом arguments. Если проверка дает правильный результат, то программа затем извлекает имена исходного и целевого файлов из массива args, присваивая их значения переменным source и dest соответственно.

Затем программа проверяет, может ли читаться исходный файл, выдает со-общение об ошибке и завершает работу, если файл не читается.

Оператор tfm fileExistsAtPath: dest isDirectory: ftsDir];

проверяет файл, который указывается переменной dest, чтобы определить, не является ли он папкой. Как вы видели выше, ответ (YES или N0) сохраняется в переменной isDir.

Если dest является папкой, то нужно добавить в конец имени этой папки имя исходного файла в качестве последнего компонента пути. Для этого используется метод работы с папками stringByAppendingPathComponent:. Например, если значением переменной source

является строка chl6/copy1.m, а значением пере-менной dest является /Users/stevekochan/progs, и это папка, то нужно изменить значение dest на /Users/steveкосhan/progs/coру 1 .т.

Метод copyPath:ToPath:handler: не допускает перезаписи файлов. Таким обра-зом, чтобы избежать ошибки, программа пытается удалить с начала целевой файл с помощью метода removeFileAtPath:handler:* На самом деле не имеет значения, выполнит л и эту работу данный метод, поскольку он в любом случае выдаст ошибку, если целевой файл не существует.

Если достигнут конец программы, то предполагается, что задача выполнена, и выдается соответствующее сообщение. Основные файловые операции: NSFileHandle

Методы из класса NSFileHandle позволяют выполнять более сложную работу с файлами. В начале этой главы мы перечислили некоторые возможности этих методов.

В общем случае при работе с файлом нужно выполнить следующие шаги.

Открыть файл и получить объект класса NSFileHandle для ссылки на этот файл в последующих операциях ввода-вы вода.

Выполнить необходимые операции ввода-вывода с открытым файлом.

Закрыть файл.

В таблице 16.6 приводятся некоторые наиболее распространенные методы NSFileHandle. В этой таблице fh — это объект NSFileHandle, data — это объект NSData, path — это объект NSString, offset — это значение типа unsigned long long. Метод Описание +(NSFileHandle *) fileHandleForReadingAtPath: path Открывает файл для чтения. +(NSFileHandle *) fileHandleFoiWritingAtPath: path Открывает файл для записи. +(NSFileHandle *) fileHandleForUpdatingAtPath: path Открывает файл для изменения (чтение и запись). -(NSData *) availableData Возвращает данные, доступные для чтения, из устройства или канала. -(NSData *) readDataToEndOfFile Читает оставшиеся данные до конца файла порциями не более (UINT_MAX) байт. -(NSData *) readDataOflength: (NSUInteger) bytes Читает заданное количество байтов {bytes) из файла. -(void) writeData: data Записывает данные (data) в файл. -(unsigned long long) offsetlnFite Получает текущее смещение в файле -(void) seekToFileOffset: offset Задает текущее смещение (offset) в файле. -(unsigned long long) seekToEndOfFile Помешает текущее смещение в конец файла. -(void) truncateFileAtOffset: offset Задает размер файла, равный o/fee/байт (с заполнением при необходимости свободного места). -(void) closeFile Закрывает файл.

Здесь не приводятся методы NSFileHandle для стандартного ввода, стандарт-ного вывода, стандартных ошибок и null-устройства. Они имеют форму fileHandleWithDevice, где обозначение Device может быть представлено как Standardlnput, StandardOutput, Standard Error или NullDevice.

Здесь также не приводятся методы для чтения и записи данных в фоновом режиме, то есть асинхронно.

Следует отметить, что класс FileHandle не предусматривает создание файлов. Это нужно делать с помощью методов FtleManager, которые были описаны выше. Например, в методах fileHandleForWritingAtPath: и fileHandleForUpdatingAlF’ath: предполагается, что файл существует, и они возвращают значение nil, если его нет. В обоих случаях смешение задастся в начале файла, поэтому запись (или чтение в режиме update) начинается с начала файла. Кроме того, если вы работали с UNIX, то, видимо, обратили внимание, что открытие файла для записи не вызывает усече-ния файла. Вы должны сделать это самостоятельно, если это вам нужно.

Программа 16.7 открывает исходный файл testfile, который мы создали в на-чале главы, читает его содержимое и копирует его в файл с именем testout. // Основные операции обработки файлов // Предполагается, что существует файл с именем "testfile" // в текущей рабочей папке #import <Foundation/NSObject.h> #import <Foundation/NSString.h> #import <Foundation/NSFileHandle.h> #import <Foundation/NSFileManager.h> #import <Foundation/NSAutoreleasePool.h> #import <Foundation/NSData.h> int main (int argc, char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; NSFileHandle *inFile, *outFile; NSData *buffer; // Открытие файла testfile для чтения inFile = [NSFileHandle fileHandleForReadingAtPath: @"testfile"]; if (inFile == nil) { NSLog (@"Open of testfile for reading failed"); (Невозможно открыть testfile для чтения) return 1; } // Создание выходного файла, если это нужно [[NSFileManager defaultManager] createFileAtPath: @"testout" contents: nil attributes: nil]; // Теперь открытие выходного файла для записи outFile = [NSFileHandle fileHandleForWritingAtPath: @"testout"]; if (outFile == nil) { NSLog (@"Open of testout for writing failed"); (Невозможно открыть testfile для записи) return 2; } // Усечение выходного файла, поскольку он может содержать данные [outFile truncateFileAtOffset: 0]; // Чтение данных из inFile и запись в outFile buffer = [inFile readDataToEndOfFile]; [outFile writeData: buffer]; // Закрытие обоих файлов [inFile closeFile]; [nutFilfi nloseFilfi]; // Проверка содержимого файла NSLog(@"%@", [NSString StringWithContentsOfFile: @"testout" encoding: NSUTF8StringEncoding error: nil]); [pool drain]; return 0; }

Вывод программы 16.7 This is a test file with some data in it. (Это тестовый файл с некоторыми данными.) Here’s another line of data. (Это еще одна строка данных.) And a third. (И третья.)

Метод readDataToEndOfFile: читает данные порциями не более UINT_MAX байт, что определено в и равно FFFFFFFF,6. Этого вполне достаточно для приложения, которое требуется написать. Мы можем также разбить эту работу для чтения и записи небольшими порциями и задать цикл для единовременной пересылки полного буфера между файлами с помощью метода readDataOfLength:. Например, размер буфера можно задать равным 8192 (8 кбайт) или 131072 (128 кбайт). Как правило, размер равен степени 2, поскольку базовая операционная система обычно выполняет свои операции ввода-вывода именно такими порциями данных. Вы можете опробовать различные значения, чтобы определить, что лучше в вашей системе.

Поделиться с друзьями: