Показаны сообщения с ярлыком NSFileHandle. Показать все сообщения
Показаны сообщения с ярлыком NSFileHandle. Показать все сообщения

2 апр. 2014 г.

Обработка файлов с помощью класса NSFileHandle

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

Инициализация NSFileHandle класса

Объект NSFileHandle создется при открытии файла для чтения, записи или обновления (чтение и запись). Это достигается с помощью fileHandleForReadingAtPath, fileHandleForWritingAtPath и методом fileHandleForUpdatingAtPath соответственно. Открыв файл, он впоследствии должен быть закрыт, когда Мы закончили работать с ним, используя метод CloseFile. Если попытка открыть файл не удается, к примеру, потому что делается попытка открыть несуществующий файл для чтения, эти методы возвращают ноль.

Например, следующий фрагмент кода открывает файл для чтения и записи, а затем закрывает его, фактически ничего не делая с файлом:

NSFileHandle *file;
file = [NSFileHandle fileHandleForWritingAtPath: @"/tmp/myfile.txt"];
if (file == nil)
        NSLog(@"Failed to open file");

[file closeFile];

NSFileHandle и позиция курсора

NSFileHandle объекты поддерживают указатель на текущей позиции в файле. Это упоминается как курсор. Когда файл открывается в первый раз курсор устанавливается в 0 (начало файла). Это означает, что любые операции чтения или записи которые Мы совершаем с помощью методов NSFileHandle начнутся с нулевой позиции курсора в файле. Для выполнения операций в разных местах в файле (например, для добавления данных в конец файла) в первую очередь необходимо стремиться к необходимости перемещения курсора в конец файла. Например, чтобы переместить текущую позицию курсора в конец файла, используйте метод seekToEndOfFile. Кроме того, seekToFileOffset позволяет указать точное местоположение в файле, к которое должен расположиться курсор. Наконец, текущее положение курсора может быть идентифицировано с помощью метода offsetInFile.

В следующем примере открывается файл для чтения, а затем выполняет ряд вызовов метода для перемещения курсора в различное местоположение файла:

NSFileHandle *file;
file = [NSFileHandle fileHandleForUpdatingAtPath: @"/tmp/myfile.txt"];
if (file == nil)
        NSLog(@"Failed to open file");

NSLog (@"Offset = %llu", [file offsetInFile]);
[file seekToEndOfFile];
NSLog (@"Offset = %llu", [file offsetInFile]);
[file seekToFileOffset: 30];
NSLog (@"Offset = %llu", [file offsetInFile]);
[file closeFile];

Курсор в файлах один из ключевых аспектов работы с файлами с помощью класса NSFileHandle, и нужно много практиковаться чтобы хорошо этот принцып понимать. Не зная позиции курсора - неизвестно откуда считаются или куда запишутся Ваши данные.

Чтение данных из файла

После того, как файл был открыт и присвоен дескриптор файла, содержимое этого файла может быть считано из текущего положения курсора. Метод readDataOfLength читает указанное число байт данных из файла, начиная с текущей позиции курсора. Например, следующий код считывает 5 байт данных из 10-й позиции в файле. Считанные данные будут хранится в объекте NSData:

NSFileHandle *file;
NSData *databuffer;

file = [NSFileHandle fileHandleForReadingAtPath: @"/tmp/myfile.txt"];
if (file == nil)
        NSLog(@"Failed to open file");

[file seekToFileOffset: 10];
databuffer = [file readDataOfLength: 5];
[file closeFile];

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

Запись в файл

Метод writeData записывает данные, содержащиеся в объекте NSData в файл, начиная с местоположения курсора. Обратите внимание, метод не дописивает данные, а перезаписывает все существующие данные в файле в соответствующем месте.

Чтобы увидеть это в действии, создадим файл с помощью текстового редактора с именем quickfox.txt, наберем следующий текст и сохраним его в каталоге /tmp:

"Быстрый коричневый кот перепрыгнул через ленивую собаку"

Далее, напишем код программы, которая открывает файл для обновления, перенесем курсор в позицию 10, а затем запишем некоторые данные в этом месте:


#import <Foundation/Foundation.h>

int main (int argc, const char * argv[])
{
    @autoreleasepool {

        NSFileHandle *file;
        NSMutableData *data;

        const char *bytestring = "коричневый кот";
        data = [NSMutableData dataWithBytes:bytestring length:strlen(bytestring)];

        file = [NSFileHandle fileHandleForUpdatingAtPath: @"/tmp/quickfox.txt"];
        if (file == nil)
                NSLog(@"Failed to open file");

        [file seekToFileOffset: 10];
        [file writeData: data];
        [file closeFile];
    }
    return 0;
}

Когда наша программа выполнится, содержимое quickfox.txt будет изменен на:
"Быстрый коричневый кот перепрыгнул через ленивую собаку". 

Усечение (обрезание) файла

Файл может быть усечен с указанным смещением курсора, используя метод truncateFileAtOffset. Чтобы удалить все содержимое файла необходимо указать положение курсора 0 при вызове этого метода:

NSFileHandle *file;
file = [NSFileHandle fileHandleForUpdatingAtPath: @"/tmp/quickfox.txt"];
if (file == nil)
    NSLog(@"Failed to open file");

[file truncateFileAtOffset: 0];
[file closeFile];

1 апр. 2014 г.

Objective-C - операции с каталогами

Понимание путей в Objective-C

Имена путей определяются с помощью конвенции UNIX. Таким образом каждый компонент пути отделяется косой чертой (/). Пути, которые не начинаются с косой черты интерпретируются относительно текущего рабочего каталога. Например, если текущий рабочий каталог /home/ ObjC/MyApp/example.m то это считается полный путь. 
Кроме того, домашний каталог текущего пользователя может быть представлен с помощью тильды (~). Например путь ~/example.m ссылается на файл с именем example.m расположенный в домашнем каталоге текущего пользователя. Домашний каталог другого пользователя можно ссылаться, задав имя пользователя с ~. Например, ~ Джон/demo.m ссылается на файл, расположенный в домашнем каталоге пользователя с именем Джон.

Инициализация объекта NSFileManager

NSFileManager *filemgr;
filemgr = [NSFileManager defaultManager];


Определение текущей директории

Текущий рабочий каталог можно идентифицировать с помощью метода currentDirectoryPath экземпляра нашего объекта NSFileManager. Текущий путь возвращается из метода в виде объекта NSString:

NSFileManager *filemgr;
NSString *currentpath;

filemgr = [NSFileManager defaultManager];
currentpath = [filemgr currentDirectoryPath];
NSLog (@"Current directory is %@", currentpath);


Изменение пути каталога / директории на другой

Текущий рабочий каталог работающей программы Objective-C может быть изменен с помощью вызова метода changeCurrentDirectoryPath. Путь к каталогу назначения передается в качестве аргумента методу экземпляра в форме объекта NSString. Обратите внимание, что этот метод возвращает логическое ДА или НЕТ если операция прошла успешно:

NSFileManager *filemgr;
NSString *currentpath;

filemgr = [NSFileManager defaultManager];
currentpath = [filemgr currentDirectoryPath];
NSLog (@"Current directory is %@", currentpath);

if ([filemgr changeCurrentDirectoryPath: @"/temp/mydir"] == NO)
        NSLog (@"Cannot change directory.");

currentpath = [filemgr currentDirectoryPath];
NSLog (@"Current directory is %@", currentpath);


Создание нового каталога / директории

Новый каталог создается с помощью метода экземпляра createDirectoryAtURL, в качестве аргумента поступает объект NSURL. Этот метод также принимает дополнительные аргументы в виде набора атрибутов для нового каталога и логическое значение, указывающее, должны ли быть созданы промежуточные каталоги, если они не существуют. Указав ноль (nil), метод будет использовать стандартные атрибуты:

NSFileManager *filemgr;

filemgr = [NSFileManager defaultManager];
NSURL *newDir = [NSURL fileURLWithPath:@"/tmp/mynewdir"];
[filemgr createDirectoryAtURL: newDir withIntermediateDirectories:YES attributes: nil error:nil];

Также после операции выполнения вернет ДА или НЕТ, в зависимости от результата выполнения.

Удаление каталога / директории

Существующий каталог может быть удален из файловой системы с помощью метода removeItemAtPath:

NSFileManager *filemgr;

filemgr = [NSFileManager defaultManager];
[filemgr removeItemAtPath: @"/tmp/mynewdir" handler: nil];


Переименование / Перемещение каталога / директории

Существующий файл или каталог может быть перемещен (переименован) с помощью метода moveItemAtURL. Этот метод принимает путь как аргумент в виде объектов NSURL и требует, чтобы путь назначения не существовал. Логический возвращаемый результат НЕТ, если произошел отказ над операцией:

NSFileManager *filemgr;

filemgr = [NSFileManager defaultManager];

NSURL *oldDir = [NSURL fileURLWithPath:@"/tmp/mynewdir"];
NSURL *newDir = [NSURL fileURLWithPath:@"/tmp/mynewdir2"];

[filemgr moveItemAtURL: oldDir toURL: newDir error: nil];

Получение списка файлов в каталоге / директории


Перечень файлов, содержащихся в указанном каталоге можно получить, используя метод contentsOfDirectoryAtPath. Этот метод принимает путь к каталогу в качестве аргумента и возвращает объект NSArray, содержащий имена файлов и подкаталогов в этом каталоге:

NSFileManager *filemgr;
NSString *currentpath;
NSArray *filelist;
int count;
int i;

filemgr = [NSFileManager defaultManager];
filelist = [filemgr contentsOfDirectoryAtPath: @"/tmp" error: nil];
count = [filelist count];

for (i = 0; i < count; i++)
        NSLog (@"%@", [filelist objectAtIndex: i]);

Получение атрибутов файла или каталога / директории

Атрибуты файла или каталога можно получить, используя метод attributesOfItemAtPath. Он принимает в качестве аргументов путь к каталогу и дополнительный объект NSError в котором хранится информация о любых ошибках. Результаты возвращаются в виде объекта словаря NSDictionary (подробнее о работе с словарных объектов относятся к объектам Objective-C NSDictionary . Ключами для этого словаря являются:


NSFileType
NSFileTypeDirectory
NSFileTypeRegular
NSFileTypeSymbolicLink
NSFileTypeSocket
NSFileTypeCharacterSpecial
NSFileTypeBlockSpecial
NSFileTypeUnknown
NSFileSize
NSFileModificationDate
NSFileReferenceCount
NSFileDeviceIdentifier
NSFileOwnerAccountName
NSFileGroupOwnerAccountName
NSFilePosixPermissions
NSFileSystemNumber
NSFileSystemFileNumber
NSFileExtensionHidden
NSFileHFSCreatorCode
NSFileHFSTypeCode
NSFileImmutable
NSFileAppendOnly
NSFileCreationDate
NSFileOwnerAccountID
NSFileGroupOwnerAccountID

Например, мы можем извлечь права, дату создания, тип файла для каталога /tmp, используя следующий фрагмент кода:

NSFileManager *filemgr;

NSDictionary *attribs;

filemgr = [NSFileManager defaultManager];
attribs = [filemgr attributesOfItemAtPath: @"/tmp" error: NULL];

NSLog (@"Created on %@", [attribs objectForKey: NSFileCreationDate]);
NSLog (@"File type %@", [attribs objectForKey: NSFileType]);
NSLog (@"POSIX Permissions %@", [attribs objectForKey: NSFilePosixPermissions]);

NSFileManager, NSFileHandle и NSData классы (миниобзор)

Foundation Framework предоставляет три класса, которые необходимы, для работы с файлами и каталогами:

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

Класс NSFileHandle предоставляется для выполнения операций с файлами более низкого уровня, таких как извлечение с определенной позиции в файле (курсор), читать и писать содержимое файла на указанное количество байт, добавление данных в существующий файл.

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