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

6 апр. 2014 г.

Определение домашней папки пользователя

Определение домашней папки пользователя

//get user home
+(NSString *)getUserHome
{
    const char *home = getpwuid(getuid())->pw_dir;
    NSString *path = [[NSFileManager defaultManager]
                      stringWithFileSystemRepresentation:home
                      length:strlen(home)];
    NSString *realHomeDirectory = [[NSURL fileURLWithPath:path isDirectory:YES] path];
    
    return realHomeDirectory;
}

3 апр. 2014 г.

Системные директории в Objective-C

Директория /tmp

Большинство операционных систем имеют стандартный каталог предоставленный специально для целей временного хранения файлов. Другие системы также обеспечивают другую временную папку для каждого пользователя. Точное место отличается в зависимости от платформы. Самым безопасным будет использование NSTemporaryDirectory(), чтобы определить соответствующий каталог. Эта функция возвращает временный каталог для текущего пользователя в виде объекта NSString.
Следующий фрагмент кода определяет и затем отображает временный каталог, используя NSTemporaryDirectory() функцию:

NSString *tempdir;
tempdir = NSTemporaryDirectory();
NSLog (@"Temp Dir = %@", tempdir);

Определение домашней папки пользователя

Домашний каталог текущего пользователя может быть определен с помощью NSHomeDirectory() функции. Эта функция не принимает аргументов и возвращает объект NSString, содержащий путь к домашней директории пользователя:

NSString *homedir;
homedir = NSHomeDirectory();
NSLog (@"Home directory of current user is %@", homedir);

Определение домашней папки конкретно заданного пользователя

Домашний каталог любого пользователя в системе может быть получен с помощью NSHomeDirectoryForUser() функции. Эта функция принимает в качестве единственного аргумента объекта NSString, содержащий имя пользователя и возвращает другой объект NSString, содержащий соответствующий домашний каталог:

NSString *homedir;
NSString *username = @"Paul";
homedir = NSHomeDirectoryForUser(username);
NSLog (@"Home directory of user %@ is %@", username, homedir);

Если заданного пользователя не существует, запрос вернет nil.

Извлечение имени файла

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

NSString *samplepath = @"/Users/demo/objc/sample.m";

NSString *filename;
filename = [samplepath lastPathComponent];
NSLog (@"lastPathComponent = %@", filename);

Извлечение расширения файла

Имена файлов после '.' имеют некое расширение. Например, расширение файла myfile.txt является TXT. Расширение файла может быть извлечено из пути с использованием метода pathExtension:

NSString *samplepath = @"/Users/demo/objc/sample.m";
NSString *pathext;
pathext = [samplepath pathExtension];
NSLog (@"pathExtension = %@", pathext);

Стандартизация пути

Удивительно, как быстро путь может осложниться, особенно когда пользователь перемещаться по файловой системе. Пакет NSUtilities предоставляет метод stringByStandardizingPath. В следующем коде Мы будем использовать этот метод, чтобы сделать упрощение пути:

Например: ~demo/objc/code/../header/./../includes/mycode.h

NSString *samplepath = @"/Users/demo/objc/code/../header/./../includes/mycode.h";
NSString *cleanpath;
cleanpath = [samplepath stringByStandardizingPath];
NSLog (@"Standardized path = %@", cleanpath);

В результате выполнения получим правильный путь: /Users/demo/objc/includes/mycode.h

Разложение пути на его составляющие директории

Метод pathComponents извлекает различные части пути, которые составляют полный путь и возвращает их в NSArray:

NSString *samplepath = @"/Users/demo/objc/code/includes/mycode.h";
NSString *component;
NSArray *pathcomponents;
pathcomponents = [samplepath pathComponents];
for (component in pathcomponents)
        NSLog (@"component = %@", component);

В результате получим массив-список директорий из которых состоит путь:

component = /
component = Users
component = demo
component = objc
component = code
component = includes
component = mycode.h


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];

NSFileManager - работа с каталогами и файлами (примеры). Часть 2

Продолжение первой части примеров по NSFileManager.

Копирование файла

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

NSFileManager *filemgr;
filemgr = [NSFileManager defaultManager];
if ([filemgr copyItemAtPath: @"/tmp/myfile.txt" toPath: @"/Users/demo/newfile.txt" error: NULL]  == YES)
        NSLog (@"Скопировано");
else
        NSLog (@"Ошибка копирования");

Удаление файла

Метод removeItemAtPath удаляет указанный файл из файловой системы. Метод принимает в качестве аргументов путь к файлу, и дополнительный объект NSError. Успех операции, как обычно - в виде возвращения логического завершения операции ДА или НЕТ:

NSFileManager *filemgr;
filemgr = [NSFileManager defaultManager];
if ([filemgr removeItemAtPath: @"/tmp/myfile.txt" error: NULL]  == YES)
        NSLog (@"Файл удален");
else
        NSLog (@"Ошибка удаления файла");

Создание ссылки на файл


Ссылка на конкретный файл может быть создана с использованием метода createSymbolicLinkAtPath. Этот метод принимает в качестве аргументов путь к ссылке, и путь к файлу, для которого эта ссылка создается и дополнительный объект NSError. Например, следующий код создает ссылку /tmpUsers/demo/myfile21.txt, которая связывает с уже существующим файлом /tmp/myfile.txt:
NSFileManager *filemgr;
filemgr = [NSFileManager defaultManager];
if ([filemgr createSymbolicLinkAtPath: @"/tmp/myfile2.txt"
                withDestinationPath: @"/tmp/myfile.txt" error: NULL] == YES)
        NSLog (@"Ссылка создана успешно");
else
        NSLog (@"Ошибка");NSFileManager *filemgr;

filemgr = [NSFileManager defaultManager];
if ([filemgr createSymbolicLinkAtPath: @"/Users/demo/file1.txt" 
                withDestinationPath: @"/tmp/myfile.txt" error: NULL] == YES)
        NSLog (@"Ссылка создана успешно");
else
        NSLog (@"Ошибка");
Чтение и запись файлов

Класс NSFileManager содержат в себе некоторые основные методы для чтения и записи файла. Но эти возможности несколько ограничены по сравнению с вариантами, предусмотренными в классе NSFileHandle (в будущей статье об этом расскажу), но тем не менее полезны и эти методы.
Во-первых, содержимое файла может быть прочитано и храниться в объекте NSData за счет использования метода contentsAtPath:
NSFileManager *filemgr;
NSData *databuffer;
filemgr = [NSFileManager defaultManager];
databuffer = [filemgr contentsAtPath: @"/tmp/myfile.txt" ];
Дальше содержимое файла в объекте NSData можно обработать, и новые данные могут впоследствии быть записаны в новый файл с помощью метода createFileAtPath:

databuffer = [filemgr contentsAtPath: @"/tmp/myfile.txt" ];
[filemgr createFileAtPath: @"/tmp/newfile.txt" contents: databuffer attributes: nil];

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

NSFileManager - работа с каталогами и файлами (примеры). Часть 1

Инициализация NSFileManager

Класс NSFileManager содержит метод класса с именем defaultManager, который используется для создания экземпляра класса. Например: получить ссылку на экземпляр объекта NSFileManager:

NSFileManager *filemgr;
filemgr = [NSFileManager defaultManager];

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

Класс NSFileManager содержит метод экземпляра с именем fileExistsAtPath, который проверяет, существует ли указанный файл. Метод принимает в качестве аргумента объект NSString, содержащий путь к файлу и возвращает логическое ДА или НЕТ, указывающее на наличие или отсутствие этого файла:
 
NSFileManager *filemgr;
filemgr = [NSFileManager defaultManager];
if ([filemgr fileExistsAtPath: @"/tmp/myfile.txt" ] == YES)
        NSLog (@"Файл присуствует");
else
        NSLog (@"Файл не найден");
 
Сравнение содержимого двух файлов

Содержимое двух файлов можно сравнить на равенство с использованием метода contentsEqualAtPath. Этот метод принимает в качестве аргументов пути к двум файлам, которые будут сопоставлены и возвращает логическое ДА или НЕТ, чтобы указать, соответствует ли содержимое этих файлов:
 
NSFileManager *filemgr;
filemgr = [NSFileManager defaultManager];
if ([filemgr contentsEqualAtPath: @"/tmp/myfile.txt" andPath: @"/tmp/sales.txt"] == YES)
        NSLog (@"Содержимое файлов одинаково");
else
        NSLog (@"Содержимое файлов разное");
 
Проверка прав файла на чтение/запись/запуск/удаление

Большинство операционных систем обеспечивают определенный уровень контроля доступа к файлу. Самый быстрый способ узнать, может ли Ваше приложение иметь доступ к использованию файла - isReadableFileAtPath, isWritableFileAtPath, isExecutableFileAtPath и метод isDeletableFileAtPath. Каждый метод принимает один аргумент в виде пути к файлу и возвращает логическое ДА или НЕТ. Например, следующий фрагмент кода проверяет ести ли доступ к файлу на запись в него:
 
NSFileManager *filemgr;
filemgr = [NSFileManager defaultManager];
if ([filemgr isWritableFileAtPath: @"/tmp/myfile.txt"]  == YES)
        NSLog (@"Разрешено для записи/редактирования данных");
else
        NSLog (@"Только чтение");
 
Перемещение/Удаление файла

Файл может быть переименован (при условии, соответствующих прав) с использованием метода moveItemAtURL. Этот метод возвращает логическое ДА или НЕТ и принимает в качестве аргументов путь для файла, который будет перемещен, путь назначения и дополнительный объект NSError, в который будет помещена информация, описывающая любые ошибки, возникающие в процессе эксплуатации. Если информация по ошибкам не требуется, этот аргумент может быть установлен в NULL. Обратите внимание, что если по такому пути файл уже существует, то эта операция не будет выполнена.
 
NSFileManager *filemgr;
filemgr = [NSFileManager defaultManager];
NSURL *oldPath = [NSURL fileURLWithPath:@"/tmp/myfile.txt"];
NSURL *newPath= [NSURL fileURLWithPath:@"/tmp/newfile.txt"];
[filemgr moveItemAtURL: oldPath toURL: newPath error: nil];
 
Продолжение в следующей части.

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 предоставляет полезный буфер хранения содержимого файла, в который можно как считать из файла так и выгрузить из него данные в файл.