Zip из командной строки - как обрезать элементы пути - PullRequest
1 голос
/ 15 июня 2011

Я выполняю команду zip из моего приложения, используя NSTask.В качестве аргументов передаются некоторые пути, которые указывают на файлы / папки, которые будут заархивированы.

Проблема в том, что без опции -j конечный zip заканчивается абсурдными путями к файлам внутри zip (например, "/ private")./var/folders/A5/A5CusLQaEo4mop-reb-SYE+++TI/-Tmp-/9101A216-5A6A-4CD6-A477-E4B86E007476-51228-00014BCB9514323F/myfile.rtf ").Однако, если я добавлю опцию -j, то я постоянно сталкиваюсь с конфликтами имен, если какой-либо файл где-то глубоко во вложенной папке имеет

. Я пытался задать путь перед выполнением NSTask:

[[NSFileManager defaultManager] changeCurrentDirectoryPath:path];

В надежде, что документация для zip говорит правду:

По умолчанию zip будет хранить полный путь ( относительно текущего каталога )

Но это не сработало, как ожидалось.Настройка параметров -j и -p и -r просто создает вышеупомянутые проблемы в различных комбинациях.

ВОПРОС:

Как взять набор каталогов, например

  • / some / long / path / sub1 / file1.txt
  • / some / long / path / sub2 / file1.txt

и заархивируйте их в архив, содержимое которого

  • / sub1 / file1.txt
  • / sub2 / file1.txt

Спасибо за любые советы по тонкостям zip.

----- РЕДАКТИРОВАТЬ

Еще одна вещь, которую я забыл добавить, это то, что исходный каталог, который передается, - это «путь», поэтому желаемый результат, на мой взгляд, также является ожидаемым результатом.

Ответы [ 2 ]

2 голосов
/ 15 июня 2011

Это не универсальное решение, поскольку оно не будет хорошо обрабатывать несколько каталогов, но решение, которое я использую для одного каталога с неизвестным содержимым (т. Е. Смешанных файлов / папок / пакетов), состоит в перечислении содержимого. каталога и добавьте их по отдельности в качестве аргументов zip, а не просто заархивируйте весь каталог сразу.

В частности:

+ (BOOL)zipDirectory:(NSURL *)directoryURL toArchive:(NSString *)archivePath;
{
//Delete existing zip
if ( [[NSFileManager defaultManager] fileExistsAtPath:archivePath] ) {
    [[NSFileManager defaultManager] removeItemAtPath:archivePath error:nil];
}

//Specify action
NSString *toolPath = @"/usr/bin/zip";

//Get directory contents
NSArray *pathsArray = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[directoryURL path] error:nil];

//Add arguments
NSMutableArray *arguments = [[[NSMutableArray alloc] init] autorelease];
[arguments insertObject:@"-r" atIndex:0];
[arguments insertObject:archivePath atIndex:0];
for ( NSString *filePath in pathsArray ) {
    [arguments addObject:filePath]; //Maybe this would even work by specifying relative paths with ./ or however that works, since we set the working directory before executing the command
    //[arguments insertObject:@"-j" atIndex:0];
}

//Switch to a relative directory for working.
NSString *currentDirectory = [[NSFileManager defaultManager] currentDirectoryPath]; 
[[NSFileManager defaultManager] changeCurrentDirectoryPath:[directoryURL path]];
//NSLog(@"dir %@", [[NSFileManager defaultManager] currentDirectoryPath]);

//Create
NSTask *task = [[[NSTask alloc] init] autorelease];
[task setLaunchPath:toolPath];
[task setArguments:arguments];

//Run
[task launch];
[task waitUntilExit];

//Restore normal path
[[NSFileManager defaultManager] changeCurrentDirectoryPath:currentDirectory];

//Update filesystem
[[NSWorkspace sharedWorkspace] noteFileSystemChanged:archivePath];

return ([task terminationStatus] == 0);
}

Опять же, я не претендую на то, что это пуленепробиваемый (и хотелось бы улучшений), но он работает при правильном архивировании любой отдельной папки.

2 голосов
/ 15 июня 2011

вместо

[[NSFileManager defaultManager] changeCurrentDirectoryPath:path];

используйте -[NSTask setCurrentDirectoryPath:] до запуска задачи. Например:

NSString *targetZipPath = @"/tmp/foo.zip";
NSArray *args = [NSArray arrayWithObjects:@"-r", targetZipPath,
    @"sub1", @"sub2", nil];
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:@"/usr/bin/zip"];
[task setArguments:args];

// set path to be the parent directory of sub1, sub2
[task setCurrentDirectoryPath:path];
…
...