精通
英语
和
开源
,
擅长
开发
与
培训
,
胸怀四海
第一信赖
QTSS支持文件系统模块,因此可以透明而又简单地和定制的文件系统协同工作。举例来说,一个QTSS文件系统模块可以允许QTSS模块读取一个定制的网络文件系统,或者一个定制的数据库。对读取文件的支持包含如下组件:
在QTSS中,文件由一个QTSS流来表示,因此您可以通过现有的QTSS流回调函数来读取文件。可用于操作文件的回调函数如下:
在QTSS中,一个文件就是一个QTSS_Object对象,该对象有其自己的对象类型,即QTSS_FileObject,这使您可以通过标准的QTSS回调函数(QTSS_GetValue,QTSS_GetValueAsString,和QTSS_GetValuePtr)来获取文件的元信息,比如文件的长度和修改日期。您可以通过标准的QTSS回调函数来将任意数量的文件系统元信息和文件对象存储在一起。举例来说,一个和POSIX文件系统协同工作的模块希望为存储POSIX文件系统描述符的文件对象添加一个属性。文件对象中还有一个QTSS流引用,在调用对文件进行操作的QTSS流例程,比如QTSS_Read时,可以使用该引用。
The sample code in 列表 3-7 中的实例代码显示了如何打开一个文件,确定文件的长度,读取整个文件,关闭文件,以及返回文件中含有的数据。
Listing 2-7 Reading a file QTSS_Error ReadEntireFile(char* inPath, void** outData, UInt32* outDataLen) { QTSS_Object theFileObject = NULL; QTSS_Error theErr = QTSS_OpenFileObject(inPath, qtssOpenFileNoFlags, &theFileObject); if (theErr != QTSS_NoErr) return theErr; // The file wasn't found or it couldn't be opened. // The file is open. Find out how long it is. UInt64* theLength = NULL; UInt32 theParamLen = 0; theErr = QTSS_GetValuePtr(theFileObject, qtssFlObjLength, 0, (void**)&theLength, &theParamLen); if (theErr != QTSS_NoErr) return theErr; if (theParamLen != sizeof(UInt64)) return QTSS_RequestFailed;; // Allocate memory for the file data. *outData = new char[*theLength + 1]; *outDataLen = *theLength; // Read the data UInt32 recvLen = 0; theErr = QTSS_Read(theFileObject, *outData, *outDataLen, &recvLen); if ((theErr != QTSS_NoErr) || (recvLen != *outDataLen)) { delete *outData; return theErr; } // Close the file. (void)QTSS_CloseFileObject(theFileObject); } |
|
文件系统模块为QTSS模块提供了一种途径,来读取特定文件系统的文件,无论该文件系统的类型是什么。典型情况下,文件系统模块处理的是文件系统中所有路径的一个子集合,但是也可能处理系统中的所有路径。如果文件系统模块只处理特定的路径子集,则通常会处理某个根路径下的所有路径。举例来说,处理存储在某个特定数据库中的文件可能只负责从/Local/database_root/目录下的所有路径。
实现一个QTSS文件系统模块首先要从注册为下面的某个角色开始:
如果文件系统模块处理的是系统中存在的文件的一个子集,则应该注册Open File Preprocess角色。举例来说,为数据库之外的文件提供服务的文件系统模块可能只处理某个根目录下面的文件。所有其它路径应该由其它可以处理这些路径的模块来负责。
如果文件系统模块实现了系统中缺省的文件系统,则应该注册Open File角色。举例来说,在一个UNIX系统上,处理Open File角色的模块可能会在服务器和标准的POSIX文件系统之间提讴歌内一个接口。
一旦模块从Open File角色或者Open File Preprocess角色返回QTSS_NoErr,就要为这个新打开的文件负责,就应该准备好处理下面这些代表该文件的角色:
请注意:模块不需要显式注册Advise File,Read File,Request Event File或者Close File 角色,也可以处理这些角色。相反,从某个打开文件的角色中返回QTSS_NoErr或者QTSS_RequestFailed的本身就说明了对特定文件对象的所有权,因此也就意味着模块已经注册了这些角色。
这个部分描述如下文件系统模块角色:
服务器会调用Open File Preprocess角色,来响应通过QTSS_OpenFileObject 回调函数打开文件的模块。模块有义务对这个角色进行处理,以确定是否处理指定需要打开的文件类型。如果要对该文件类型进行处理,而且该文件存在,则模块就打开该文件,更新由服务器提供的文件对象,然后返回QTSS_NoErr。
Open File Preprocess角色在被调用的时候会收到一个QTSS_OpenFile_Params结构,该结构定义如下:
typedef struct |
|
inPath
这是一个以null结尾的C字符串,包含将要被打开的文件的全路径。
inFlags
这是一个文件打开的标志参数,指定调用QTSS_OpenFileObject 的模块是否可以处理异步的度操作(qtssOpenFileAsync),或者是否希望以从头到尾的顺序读取文件(qtssOpenFileReadAhead)。
inFileObject
这是一个QTSS对象,模块如果可以打开由inPath参数指定的文件,则会更新这个对象。
如果指定的文件是模块要处理的文件,则模块应该做好打开和配置文件所需要的一切必工作。它可以使用inFileObject对象来为该文件存储任何专门用于模块的信息。此外,模块还应该设定文件对象中qtssFlObjLenth和qtssFlObjModDate属性的值。
如果指定的文件是模块要处理的,但是在准备配置文件的过程中发生错误,则模块应该返回QTSS_RequestFailed。
如果注册了Open File Preprocess角色的所有模块都返回QTSS_FileNotFound,则服务器会调用一个注册了Open File角色的模块。
希望被以Open File Preprocess角色调用的模块必须在其Register角色中调用QTSS_AddRole函数,并指定QTSS_OpenFilePreprocess_Role作为角色参数。注册为这个角色的模块也必须处理下面这些角色,但是不必显式地加以注册: Advise File,Read File,Request Event File,和Close File。
在所有注册了Open File Preprocess角色的所有模块都被调用,并且都返回QTSS_FileNotFound的时候,服务器会调用注册了Open File角色的模块。只有一个模块可以注册Open File角色,该模块就是在QTSS启动的时候第一个注册该角色的模块。
和以Open File Preprocess角色被调用的模块一样,模块有义务对Open File角色进行处理,以确定是否可以处理即将被打开的文件的类型。如果要处理该类型的文件,而且文件存在,则模块就打开该文件,更新由服务器提供的文件对象,并返回QTSS_NoErr。
模块在被调用的时候会收到一个QTSS_OpenFile_Params结构,该结构定义如下:
typedef struct |
|
inPath
这是一个以null结尾的C字符串,包含将要被打开的文件的全路径。
inFlags
这是一个文件打开的标志参数,指定调用QTSS_OpenFileObject 的模块是否可以处理异步的度操作(qtssOpenFileAsync),或者是否希望以从头到尾的顺序读取文件(qtssOpenFileReadAhead)。
inFileObject
这是一个QTSS对象,模块如果可以打开由inPath参数指定的文件,则会更新这个对象。
如果指定的文件是模块要处理的文件,则模块应该做好打开和配置文件所需要的一切必工作。它可以使用inFileObject对象来为该文件存储任何专门用于模块的信息。此外,模块还应该设定文件对象中qtssFlObjLength和qtssFlObjModDate属性的值。
如果指定的文件是模块要处理的,但是在准备配置文件的过程中发生错误,则模块应该返回QTSS_RequestFailed。
希望被以Open File Preprocess角色调用的模块必须在其Register角色中调用QTSS_AddRole函数,并指定QTSS_OpenFile_Role作为角色参数。注册为这个角色的模块也必须处理下面这些角色,但是不必显式地加以注册:Advise File,Read File,Request Event File,和Close File。
当模块(或者服务器)为某个文件对象调用QTSS_Advise回调函数,以通知文件系统模块文件的指定部分很快就会被读取的时候,服务器就会以Advise File角色调用各个模块。
Advise File角色在被调用的时候会接收到一个QTSS_AdviseFile_Params结构,该结构定义如下:
typedef struct |
|
inFileObject
这是个文件对象,代表已经打开的文件。文件系统模块使用文件对象来确定与调用QTSS_Advise回调函数相关联的文件。
inPosition
相对于文件开头的偏移量,以字节数记,表示即将被读取部分的开头。
inSize
将被读取的部分的字节数。
服务器并不要求文件系统模块在处理这个角色的时候做任何事情,但是这个角色可以使模块有机会读取文件的指定部分。
文件系统模块并不需要显式注册这个角色。
模块在完成这个角色的处理之后,应该总是返回QTSS_NoErr。
当模块(或者服务器)为某个文件对象调用QTSS_Read回调函数,以读取相应的文件时,服务器会以Read File角色调用各个模块来进行响应。
Read File角色在被调用的时候会接收到一个QTSS_ReadFile_Params 结构,该结构定义如下:
typedef struct |
|
inFileObject
这是一个文件对象,表示即将被读取的文件。文件系统模块通过这个文件对象来确定与之前调用的QTSS_Read函数相关联的文件。
inFilePosition
相对于文件开头的偏移量,以字节数记,表示即将被读取部分的开头。服务器对文件的位置进行维护,将它作为文件对象的属性进行存储,因此文件系统模块并不一定要在内部对文件的位置进行缓存,而是在任何时候都可以得到这个位置信息。
ioBuffer
这是一个缓冲区的指针,文件系统模块将读到的数据放置到这个缓冲区上。
ioBufLen
ioBuffer指向的缓冲区的长度。
outLenRead
实际读取到的字节数。
文件系统模块应该尽可能将文件数据填充到由ioBuffer参数指向的缓冲区,这些数据是从文件中读出来的,其在文件中的起始位置由inFilePosition参数来指定。
如果文件是以qtssOpenFileAsync标识打开的,则在读取数据可能导致线程阻塞的时候,模块应该返回QTSS_WouldBlock。否则,模块将会阻塞线程,直到得到所有的数据。当ioBuffer指向的缓冲区满,或者到达文件的尾部,文件系统模块应该将outLenRead参数设置为已经读取到的字节数,并返回QTSS_NoErr。
如果因为某种原因导致读操作失败,则处理这个角色的文件系统模块应该返回QTSS_RequestFailed。
文件系统模块不需要显式注册这个角色。
当模块(或者服务器)为某个文件对象调用QTSS_CloseFile回调函数,来关闭某个已经打开的文件时,服务器会调用各个模块的Close File角色进行相应。
Close File 角色在被调用的时候会接收到一个QTSS_CloseFile_Params 结构,该结构定义如下:
typedef struct |
|
inFileObject
这是一个文件对象,表示即将被关闭的文件。文件系统模块使用这个文件对象来确定与之前调用的QTSS_Close函数相关联的文件。
处理这个角色的模块应该释放之前为这个即将被关闭的文件创建的任何数据结构。
对于任何给定的文件对象,这个角色是文件系统模块中最后一个被调用的角色。
文件系统模块不需要显式注册这个角色。
模块在处理完成这个角色之后,应该总是返回QTSS_NoErr。
当模块(或者服务器)调用QTSS_RequestEvent回调函数时,服务器会调用各个模块的Request Event File角色来进行响应。如果模块或者服务器调用QTSS_OpenFileObject函数,并指定qtssOpenFileAsync标识,则处理该文件对象的文件系统模块可能会从其Read File角色返回QTSS_WouldBlock。出现这种情况时,QTSS_Read函数的调用者可能会调用QTSS_RequestEvent回调函数,来告诉服务器QTSS_Read的调用者希望在数据可以读取的时候得到通知。
Request Event File角色在被调用的时候会接收带一个QTSS_RequestEventFile_Params结构,该结构定义如下:
typedef struct |
|
inFileObject
这是一个文件对象,表示被请求通知的文件。文件系统模块使用这个文件对象来确定与之前调用的QTSS_RequestEvent 函数相关联的文件。
inEventMask
事件掩码,指定请求通知的事件类型。可能的值为QTSS_ReadableEvent和QTSS_WriteableEvent。
如果文件系统模块正在实现的文件系统支持通知,则文件系统模块应该进行一切必要的准备,以接收与之前调用过的QTSS_RequestEvent回调函数相关联的文件的事件。当文件变为可读的时候,文件系统模块应该调用QTSS_SignalStream回调函数,并传入该文件对象的流引用(这个流引用可以通过访问对象的qtssFlObjStream属性得到)。调用QTSS_SignalStream函数可以告诉服务器应该将“文件现在已经可读”的消息通知QTSS_RequestEvent函数的调用者。
文件系统模块不需要显式注册这个角色。
模块在处理完成这个角色之后,应该总是返回QTSS_NoErr。
列表 3-8中的实例代码处理的是Open File角色,但是也可以用于处理Open File Preprocess角色。这段代码将POSIX文件系统层用作文件系统,而且不支持异步I/O。
Listing 2-8 Handling the Open File Role QTSS_Error OpenFile(QTSS_OpenFile_Params* inParams) |
|
如果模块或者服务器调用QTSS_OpenFileObject 函数,并在调用时指定qtssOpenFileAsync标志,则处理该文件对象的文件系统模块可能在其QTSS_ReadFile_Role角色函数中返回QTSS_WouldBlock。一旦这种情况出现,QTSS_Read函数的调用者可能希望在被请求的数据变为可读的时候得到通知。通过调用QTSS_RequestEvent回调函数可以做到这点,该函数告诉服务器调用者希望在可以从文件读取数据的时候得到通知。
并不是所有文件系统都支持通知机制,而且如果支持的话,每个文件系统架构的通知机制也有各自的特殊之处。因此,一个文件系统模块是否支持通知机制,取决于文件系统模块开发者的考虑。一般地说,文件系统模块支持异步通知且不会在QTSS_ReadFile_Role角色中阻塞会更好一些,因为阻塞在一个文件操作中,可能会导致很多服务器向客户提供的服务中断。
有两个工具可以帮助文件系统模块实现通知机制: