2017-09-15 19 views
2

이전의 MoreFilesX, FSExchangeObjectsCompat에는 "두 파일간에 데이터를 교환하는"훌륭한 기능이있었습니다. 일반적으로 임시 저장 파일을 작성한 후 FSExchangeObjectsCompat를 호출하여 새로 저장된 임시 파일을 이전 "원본"파일과 교환하는 안전한 저장 방법의 일부로 사용되었습니다.Carbon FSExchangeObjectsCompat 호출을 수행하는 코코아 메서드는 무엇입니까?

HFS + 볼륨에서 결코 실패하지 않은 APFS 볼륨의 High Sierra에서이 기능을 사용하는 데 실패했습니다. 놀랄 일도 아니고 많은 전화가 사용되지 않습니다.

하지만 같은 일을하는 Cocoa NSFileManager 방법은 무엇입니까?

답변

1

하위 수준 기능을 사용하여 비슷한 작업을 수행 할 수 있습니다. 다음은 10.12 이전 SDK와 함께 사용하도록 작성한 코드입니다. 10.12 SDK 이상에서 컴파일하는 경우 다소 간단하게 만들 수 있으며 배포 대상이 10.12 이상이면 더 간단하게 만들 수 있습니다.

#ifndef RENAME_SWAP 
#define RENAME_SWAP 0x00000002 
#endif 

/*! 
    @function ExchangeFiles 

    @abstract Given full paths to two files on the same volume, 
       swap their contents. 

    @discussion This is often part of a safe-save strategy. 

    @param  inOldFile Full path to a file. 
    @param  inNewFile Full path to a file. 
    @result  0 if all went well, -1 otherwise. 
*/ 
int ExchangeFiles(const char* inOldFile, const char* inNewFile) 
{ 
    int result = -1; 
    static dispatch_once_t sOnce = 0; 
    static renameFuncType sRenameFunc = NULL; 
    // Try to get a function pointer to renamex_np, which is available in OS 10.12 and later. 
    dispatch_once(&sOnce, 
     ^{ 
      sRenameFunc = (renameFuncType) dlsym(RTLD_DEFAULT, "renamex_np"); 
     }); 

    // renamex_np is only available on OS 10.12 and later, and does not work on HFS+ volumes 
    // but does work on APFS volumes. Being the latest and greatest, we try it first. 
    if (sRenameFunc != NULL) 
    { 
     result = (*sRenameFunc)(inOldFile, inNewFile, RENAME_SWAP); 
    } 

    if (result != 0) 
    { 
     // exchangedata is an older function that works on HFS+ but not APFS. 
     result = exchangedata(inOldFile, inNewFile, 0); 
    } 

    if (result != 0) 
    { 
     // Neither function worked, we must go old school. 
     std::string nameTemplate(inOldFile); 
     nameTemplate += "-swapXXXX"; 
     // Make a mutable copy of the template 
     std::vector<char> workPath(nameTemplate.size() + 1); 
     memcpy(&workPath[0], nameTemplate.c_str(), nameTemplate.size() + 1); 
     mktemp(&workPath[0]); 
     std::string tempPath(&workPath[0]); 

     // Make the old file have a temporary name 
     result = rename(inOldFile, tempPath.c_str()); 

     // Put the new file data under the old name. 
     if (result == 0) 
     { 
      result = rename(inNewFile, inOldFile); 
     } 

     // Put the old data under the new name. 
     if (result == 0) 
     { 
      result = rename(tempPath.c_str(), inNewFile); 
     } 
    } 

    return result; 
} 
2
+0

이것이 확실한 방법이지만 실제로 replaceItemAtURL을 withItemAtURL과 "교환"하는 것은 아닙니다. 이 작업을 수행 한 후 원본 파일은 동일한 디렉토리의 backupItemName에 저장되며 FSExchangeObjectsCompat()와 동일한 기능을 수행하려면 withItemAtURL과 교환해야합니다. – SMGreenfield

+0

'backupItemName'을 제공하는 것은 선택 사항입니다. 해당 옵션이나 옵션을 전달하지 않으면 구현시 찾고있는 유형의 교환을 수행 할 수 있습니다. –

+0

향후 참조를 위해 withItemAtURL의 "new"파일은 replaceItemAtURL에서 파일을 대체 한 후에 항상 삭제됩니다. replaceItemAtURL의 "원본"파일은 제공된 경우 backupItemName에 복사되며 NSFileManagerItemReplacementWithoutDeletingBackupItem 옵션 플래그가 지정되어 있지 않으면 삭제됩니다. 이것은 교환과 정확히 같지 않지만 충분히 가깝습니다. renamex_np를 10.12 이상으로 사용하거나 APFS가있을 때 이것이 더 우수하거나 선호되는지 확실하지 않습니다. – SMGreenfield