2011-12-23 46 views
2

有沒有一種很好的方法來複制一些文件或目錄(包括文件和子目錄)在Mac OS塊與目標c?每塊文件複製塊

+1

你究竟想達到什麼目的?你爲什麼要複製它塊?我們在談論什麼操作系統?蘋果系統? iOS版?還有別的嗎? – Codo 2011-12-23 11:22:54

+0

你認爲「塊每塊」是什麼意思? – 2011-12-23 12:43:55

+0

對不起。我們在談論MacOS。我需要暫停複製過程的能力,然後在每個下一個塊之後,我將能夠檢查標誌,然後暫停或恢復(如果它暫停)過程。 – Kira 2011-12-23 16:07:50

回答

2

您可以通過創建一個NSInputStreamNSOutputStream並在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]; 
} 

複製一個目錄的內容將需要枚舉整個目錄的內容。您可以使用-[NSFileManager enumeratorAtPath:]創建NSDirectoryEnumerator的實例。

一旦你的枚舉,你叫nextObject然後拿到文件屬性:

  • 如果該文件是一個目錄,您可以創建在目標目錄
  • 一個新的目錄如果該文件是一個普通的文件,您將啓動文件複製任務並等待直到完成處理程序被調用。
+0

謝謝,但我有兩個問題。這是一個非常好的主意,每個塊複製文件?如果我用這種方式複製文件,例如FSCopyObjectAsync,複製速度如何? – Kira 2011-12-24 04:24:28

+0

我認爲使用'FSFileOperation'可以更高效。該操作將進行預檢,因此啓動需要更長的時間。但它也可能使用一些優化來提高I/O性能,如將文件映射到內存中。 – 2011-12-24 11:08:05

+0

如果你想分塊複製,請不要忘記,資源分叉,權限,元數據等。 – 2011-12-30 13:14:14

0

您可以使用-[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); 
+0

-_-你真的看過我的問題嗎? – Kira 2011-12-23 16:08:12

+0

是的,我做了,但我誤解了它。我對這個答案感到羞愧。 – 2011-12-23 21:13:07

+0

我認爲這是我的錯誤在壞的問題結構和我的英語不好=) – Kira 2011-12-24 04:30:05