Блок за блок копирование файлов
Есть ли хороший способ скопировать некоторый файл или каталог (с файлами и подкаталогами) на блок в Mac OS с целью c?
2 ответа
Решение
Вы можете скопировать файл на блоки, создав NSInputStream
и NSOutputStream
и планирование их в NSRunLoop
, Затем, когда вы получаете байты из входного потока, вы записываете их в буфер, а когда выходной поток готов, вы копируете содержимое буфера в него.
@synthesize numberOfBytesTransferred = _numberOfBytesTransferred;
static const NSUInteger blockSize = 65536; // should be adjusted
- (void)startWithSourcePath:(NSString *)srcPath
destinationPath:(NSString *)dstPath
completionHandler:(void (^)(NSUInteger, NSError *))completionHandler
{
_buffer = malloc(blockSize);
_numberOfBytesTransferred = _bufferLength = _bufferOffset = 0;
_completionHandler = [completionHandler copy];
_srcStream = [[NSInputStream alloc] initWithFileAtPath:srcPath];
_dstStream = [[NSOutputStream alloc] initToFileAtPath:dstPath append:NO];
_srcStream.delegate = self;
_dstStream.delegate = self;
[_srcStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
[_dstStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
[_srcStream open];
[_dstStream open];
}
- (void)processStreams
{
if ( _srcStream.hasBytesAvailable && ! _bufferLength )
_bufferLength = [_srcStream read:_buffer maxLength:blockSize];
if ( _dstStream.hasSpaceAvailable && _bufferLength ) {
NSInteger length = [_dstStream write:_buffer + _bufferOffset maxLength:_bufferLength];
_bufferOffset += length;
_bufferLength -= length;
}
if ( _bufferOffset && !_bufferLength ) {
[self willChangeValueForKey:@"numberOfBytesTransferred"];
_numberOfBytesTransferred += _bufferOffset;
_bufferOffset = 0;
[self didChangeValueForKey:@"numberOfBytesTransferred"];
}
if ( _dstStream.hasSpaceAvailable && NSStreamStatusAtEnd == _srcStream.streamStatus ) {
[_srcStream close];
[_dstStream close];
_completionHandler(_numberOfBytesTransferred, nil);
}
}
- (void)cancel
{
[_srcStream close];
[_dstStream close];
}
- (void)pause
{
_paused = YES;
}
- (void)resume
{
_paused = NO;
[self processStreams];
}
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode
{
if ( NSStreamEventErrorOccurred == eventCode ) {
[_srcStream close];
[_dstStream close];
_completionHandler(_numberOfBytesTransferred, stream.streamError);
return;
}
if ( ! _paused )
[self processStreams];
}
Копирование содержимого каталога потребует перечисления через содержимое каталога. Вы можете создать экземпляр NSDirectoryEnumerator
с -[NSFileManager enumeratorAtPath:]
,
Когда у вас есть счетчик, вы звоните nextObject
затем получите атрибуты файла:
- Если файл является каталогом, вы создаете новый каталог в каталоге назначения
- Если файл является обычным файлом, вы запускаете задачу копирования файла и ждете, пока не будет вызван обработчик завершения.
Вы можете скопировать файл или каталог с -[NSFileManager copyItemAtPath:toPath:error:]
,
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *srcPath = @"/Users/nicolas/Documents/Xcode projects";
NSString *dstPath = @"/Users/nicolas/Desktop/Backup/Xcode projects";
NSError *error;
if ( ! [fileManager copyItemAtPath:srcPath toPath:dstPath error:&error] )
NSLog(@"Copy error: %@", error);