Futurebasic/语言/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 头文件中找到)
struct FSSpec {
short vRefNum;
long parID;
StrFileName name; /* a Str63 */
};
struct FSRef {
UInt8 hidden[80]; /* private to File Manager*/
};
可能对你的代码产生最大影响的差异是,FSRef 不能表示不存在的项,并且 FSRef 的不透明数据结构,在上面定义为隐藏的 80 字节数组,未被记录。特别地,FSRef 不包含它所指向的项的名称,这与 FSSpec 不同。当你考虑到 Mac OS X 允许使用包含 Unicode 字符的文件名,并且最大长度为 255 个 UniChar 时,这并不奇怪。与 FSSpec 的静态功能相比,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 的原生处理,允许我们的函数像这样编写
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
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 中获取文件名,用户只需查看它的结构或记录,就像这样
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