跳轉至內容

Futurebasic/語言/fsref 遺留

來自華夏公益教科書,開放的書籍,開放的世界

FSRef 結構 - 遺留討論

[編輯 | 編輯原始碼]

在 OS X 中訪問檔案和資料夾的首選方法。

與 FSSpec 不同,FSSpec 限制檔案和資料夾名稱為 31 個字元,而 FSRef 旨在處理較長的 Unicode 檔名以及 OS X 更強大的需求。

在 FB 和 FBtoC 中討論 FSRef 會很困難,因為沒有將它們的 功能與 FSSpec 進行比較。雖然 FSSpec 在 Carbon API 中可能已經過時 - 與民間傳說相反,它們還沒有被棄用 - FB 檔案和資料夾功能被設計為利用 FSSpec(FB 的較舊的“工作目錄”功能早已過時,並且在 OS X 中不受推薦也不受支援)。儘管如此,FB 仍然可以適應處理 FSRef,無需太多痛苦。另一方面,FBtoC 提供對 FSRef 的原生支援。

雖然使用者能夠直接訪問 FSSpec 的三個元件 - 檔案或資料夾名稱、卷引用號和其父級的 ID,但 FSRef 對使用者來說是“不透明的”。這意味著從 FSRef 中獲取資訊需要輔助 Toolbox 函式。

當檢查它們的結構時,FSSpec 和 FSRef 之間的差異顯而易見(這些定義在 Carbon Files.h 標頭檔案中找到)

FSSpec 結構

struct FSSpec {
  short         vRefNum;
  long          parID;
  StrFileName   name;          /* a Str63 */
};

FSRef 結構

struct FSRef {
  UInt8         hidden[80];    /* private to File Manager*/
};

可能對你的程式碼產生最大影響的差異是,FSRef 不能表示不存在的項,並且 FSRef 的不透明資料結構,在上面定義為隱藏的 80 位元組陣列,未被記錄。特別地,FSRef 不包含它所指向的項的名稱,這與 FSSpec 不同。當你考慮到 Mac OS X 允許使用包含 Unicode 字元的檔名,並且最大長度為 255 個 UniChar 時,這並不奇怪。與 FSSpec 的靜態功能相比,FSRef 是動態的。

在 FB 中建立 FSRef 檔案引用

[編輯 | 編輯原始碼]

FB 的檔案和資料夾功能是在 FSSpec 統治的時代編寫的。它們最常見的用途之一是在使用 FB 的 Files$ 函式開啟檔案或資料夾時。這裡我們看到 FB 的程式碼來獲取文字檔案的 FSSpec

dim as FSSpec   fs
dim as str255  fStr

fStr = Files$( _FSSpecOpen, "TEXT", "Open text file...", fs )
  long if ( fStr[0] )
    // Do something with your text file FSSpec
  xelse
    // User canceled
  end if

為了使用 FB 的 Files$ 函式獲取更通用且 OS X 友好的 FSRef,需要將生成的 FSSpec 轉換為 FSRef。這需要多幾行程式碼

dim as FSSpec  fs
dim as FSRef   fref
dim as str255  fStr

fStr = Files$( _FSSpecOpen, "TEXT", "Open text file...", fs )
  long if ( fStr[0] )
    // Convert FSSpec to FSRef
    err = fn FSpMakeFSRef( #fs, @fref)
    long if ( err == _noErr )
      // Do something with your text file FSRef
     end if
  xelse
    // User canceled
  end if

在 FBtoC 中建立 FSRef 檔案引用

[編輯 | 編輯原始碼]

最後,FBtoC 提供對 FSRef 的原生處理,允許我們的函式像這樣編寫

dim as FSRef   fref
dim as str255  fStr

fStr = files$( _FSRefOpen, "TEXT", "Open text file...", fsRef )
  long if ( fStr[0] )
    // Do something with your text file FSRef
  xelse
    // User canceled
  end if

在 FB 和 FBtoC 中建立 FSRef 檔案引用

[編輯 | 編輯原始碼]

結合這些簡單的方法,這個例子在 FB 和 FBtoC 中都返回了 FSRef

 dim as str255  fileName, s
 dim as FSSpec   fs
 dim as FSRef    fsRef
 dim as OSErr    err
'~'1

 #if ndef _FBtoC

 s = "Get file FSSpec in FB"
 fileName = files$( _FSSpecOpen,, s, fs )
  long if ( fileName[0] )
    // Convert FSSpec to FSRef
    err = fn FSpMakeFSRef( #fs, @fsRef)
    long if (err == _noErr )
      // Do something with your FSRef
    end if
  xelse
    // User canceled
  end if

 #else

 s = "Get file FSRef in FBtoC"
 fileName = files$( _FSRefOpen,, s, fsRef )
   long if fileName[0]
    //  Do something with your FSRef
   xelse
     // User canceled
   end if

 #endif

使用 FSSpec 和 FSRef 獲取檔名

[編輯 | 編輯原始碼]

要從 FSSpec 中獲取檔名,使用者只需檢視它的結構或記錄,就像這樣

myFileName = myFSSpec.name

當然,生成的 檔名限制為 31 個字元,對於 OS X 中更長的名稱,它會被截斷,幷包含垃圾字元。

從 FSRef 中獲取檔名稍微困難一些,但這個函式應該可以完成任務

local fn GetLongFileNameFromFSRef$( fsRef as ^FSRef )
 dim as str255      @ name
 dim as HFSUniStr255    hsfName
 dim as CFStringRef     cfStr
 dim as OSErr           err
 dim as boolean       result
'~'1

 err = fn FSGetCatalogInfo( #fsRef, _kFSCatInfoNone, #0, hsfName, #0, #0)
 if err then stop "FSGetCatalogInfo Error:" + str$( err )
  long if ( err == _noErr )
    cfStr = fn CFStringCreateWithCharacters( 0,hsfName.unicode[0], hsfName.length )
      long if ( cfStr )
        result = fn CFStringGetPascalString( cfStr, @name, sizeof( name ), _kCFStringEncodingMacRoman )
        CFRelease( cfStr )
      end if
  end if

end fn = name
華夏公益教科書