Программирование на Objective-C 2.0
Шрифт:
Если метод чтения обнаруживает конец файла без чтения каких-либо данных, он возвращает пустой объект NSData (то есть буфер, не содержащий никаких данных). Мы можем применять к буферу метод length и проверять его на равенство нулю, чтобы определить, остались ли какие-то данные для чтения из файла.
Если мы открываем файл для изменения, смешение устанавливается на начало файла. Это смешение можно изменить путем поиска внутри файла и затем выполнить в файле операции чтения или записи. Например, для поиска 10-го байта в файле с описателем databaseHandle можно написать в сообщении следующее выражение. [databaseHandle seekToFileOffset: 10];
Для указания относительных позиций в файле нужно получитьтекущее сме-щение в файле и затем добавлять
Для смещения на пять целых данных в файле можно написать следующее. [databaseHandle seekToFileOffet: [databaseHandle offsetlnFile] - 5 * sizeof (int)];
Программа 16.8 добавляет содержимое одного файла ко второму. Второй файл открывается для записи, выполняется поиск конца этого файла и затем содержимое первого файла записывается во второй. // Добавление содержимого файла "fileA" в конец файла "fileB" #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 * poo) = [[NSAutoreleasePool alloc] init]; NSFileHandle *inFile, *outFile; NSData *buffer; // Открытие файла fileA для чтения inFile = [NSFileHandle fileHandleForReadingAtPatti: @"fileA*']; if (inFile == nil) { NSLog (@"Open of fileA for reading failed"); return 1; } // Открытие файла fileB для изменения outFile = [NSFileHandle fileHandleForWritingAtPath: @"fileB"]; if (outFile == nil) { NSLog (@"Open of fileB for writing failed"); return 2; } // Поиск конца outFile [outFile seekToEndOfFile]; // Чтение inFile и запись его содержимого в outFile buffer = [inFile readDataToEndOfFile]; [outFile writeData: buffer]; // Закрытие обоих файлов [inFile closeFile]; [outRle closeFile]; [pool drain]; return 0; }
Содержимое FileA перед запуском программы 16.8 This is line 1 in the first file. (Это строка 1 в первом файле) This is line 2 in the first file. (Это строка 2 в первом файле)
Содержимое FileB перед запуском программы 16.8 This is line 1 in the second file. (Это строка 1 во втором файле) This is line 2 in the second file. (Это строка 2 во втором файле)
Вывод программы 16.8 Contents of fileB (Содержимое fileB) This is line 1 in the second file. This is line 2 in the second file. This is line 1 in the first file. This is line 2 in the first file.
Вывод программы показывает, что содержимое первого файла успешно до-бавлено в конец второго файла. seekToEndOfFile возвращает текущее смещение файла после выполнения поиска. В данном случае мы игнорируем эту инфор-мацию, но она позволяет получить размер файла. Упражнения
Внесите изменения в программу копирования (программа 16.6), чтобы она допускала более одного исходного файла для копирования в папку, аналогично стандартной команде UNIX ср. Например, команда $ copy copyl .m filel .т file2.m progs должна копировать три файла (copyl.m, filel.m и file2.m) в папку progs. Предусмотрите, что если указано более одного файла, то последним аргументом на самом деле является существующая папка.
Напишите средство командной строки с именем myfind, которое принимает два аргумента. Первый из них указывает начальную папку для поиска, а вто-рой- имя файла, который нужно найти. Например, командная строка $ myfind /Users proposai.doc /Users/stevekochan/MyDocuments/proposals/proposal.doc $ начинает поиск в файловой системе с /Users, чтобы найти файл proposal.doc. Выведите полный путь к файлу, если он найден (в том виде, как показано выше), или соответствующее сообщение, если он не найден.
Напишите вашу собственную версию стандартных средств UNIX basename и dirname.
Используя класс NSProcessInfo, напишите программу, которая выводит всю
информацию, возвращаемую каждым из ее методов-получателей (getter).Используя функцию NSTemporaryOirectory из NSPathUtilities.h и метод NSProcessInfo globallyUniqueString, описанные в этой главе, добавьте в NSString категорию с именем TempFiles и определите в ней метод с именем temporaryFileName, который возвращает при каждом вызове новое уникальное имя файла.
Внесите изменения в программу I6.7, чтобы в файле выполнялись чтение и запись kBufSize байт, причем kBufSize нужно определить в начале вашей программы. Обязательно проверьте эту профамму на больших файлах (размером больше kBufSize байт).
Откройте файл, считывайте его содержимое по 128 байт и выводите эти данные на терминал. Используйте метод FileHandle fileHandleWithSlandardOutput, чтобы получить описатель для вывода на терминал.
Глава 17. Управление памятью
На протяжении этой книги мы неоднократно затрагивали тему управления па-мятью. К этому моменту вам должно быть понятно, в каких случаях вы должны сами освобождать память, занятую объектами, и в каких случаях вы не обязаны это делать. Рассматривая даже небольшие примеры, мы постоянно подчеркивали, насколько важно уделять внимание управлению памятью для освоения практики надежного программирования и разработки программ, не допускающих утечки памяти.
Продуманное использование памяти может оказаться критически важным для работы приложения. Например, при создании интерактивного приложения для рисования многих объектов необходимо следить, чтобы по мере выполнения программы количество потребляемых ресурсов памяти не увеличивалось. В таких случаях вы обязаны аккуратно управлять этими ресурсами и освобождать их, когда они становятся не нужны. Это означает, что ресурсы следует освобождать во время выполнения программы, не дожидаясь ее окончания.
В этой главе мы обсудим стратегию выделения памяти в Foundation, пул ав-томатического высвобождения (autorelease pool) и идею «удержания» (retain) объектов. Вы узнаете также о счетчике ссылок (reference count) объекта и о сборке мусора (garbage collection), которая облегчает задачу удержания и последующего высвобождения объектов. Однако, как вы увидите, сборку мусора нельзя ис-пользовать для приложений iPhone, поэтому вы должны знать способы управления памятью, которые описываются в этой книге. 17.1. Автоматически высвобождаемый пул
Вы уже знакомы с автоматически высвобождаемым пулом (пулом автомати-ческого освобождения памяти) из примеров во второй части книги. При работе с программами Foundation вы должны создавать этот пул для работы с объектами Foundation. Именно в этом пуле программа следит за объектами для их даль-нейшего высвобождения. Как уже говорилось, пул в приложении можно задать с помощью следующего вызова. NSAutoreleasePool * pool = [ [ N SAutor el ease Poo I alloc] init];
После создания этого пула Foundation автоматически добавляет н него оп-ределенные массивы, строки, словари и другие объекты. Закончив использование пула, можно освободить память, которую он использует, отправив сообщение drain. [pool drain];
Автоматически высвобождаемый пул называется так потому, что любые объекты, которые помечаются как автоматически высвобождаемые (autorelease) и поэтому добавляются в этот пул, автоматически высвобождаются, когда выс-вобождается сам пул. В программе можно иметь несколько autorelease-пулов, и они могут быть также вложенными.
Если программа создает много временных объектов (что часто происходит при выполнении кода в цикле), может потребоваться создание нескольких autorelease-пулов. Например, в следующем фрагменте кода показано, как со-здавать autorelease-пулы для высвобождения временных объектов, создаваемых на каждом шаге цикла for. NSAutoreleasePool *tempPool; for (i = 0; i < n; ++i) { tempPool = [[NSAutoReleasePool alloc] init]; ... // здесь выполняется много работы с временными объектами [tempPool drain]; }