www.pudn.com > File_SD_OS.rar > file.C


/****************************************Copyright (c)************************************************** 
**                               广州周立功单片机发展有限公司 
**                                     研    究    所 
**                                        产品一部  
** 
**                                 http://www.zlgmcu.com 
** 
**--------------文件信息-------------------------------------------------------------------------------- 
**文   件   名: file.c 
**创   建   人: 陈明计 
**最后修改日期: 2004年4月1日 
**描        述: 文件系统的文件基本操作程序 
**               
**--------------历史版本信息---------------------------------------------------------------------------- 
** 创建人: 陈明计 
** 版  本: v1.00 
** 日 期: 2003年9月9日 
** 描 述: 原始版本 
** 
**--------------当前版本修订------------------------------------------------------------------------------ 
** 修改人: 陈明计 
** 日 期: 2004年7月12日 
** 描 述: 更正一个BUG 
** 
**--------------当前版本修订------------------------------------------------------------------------------ 
** 修改人: 陈明计 
** 日 期: 2004年11月4日 
** 描 述: 修改多字节读取和写入函数 
** 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
#define IN_FILE 
#include "config.h" 
 
static MY_FILE FileInfo[MAX_OPEN_FILES];        /* 打开文件信息表 */ 
 
extern uint32 _GetFDTInfo(char *FDTName, char *DirFileName); 
extern char * FsStrCopy(char *source); 
 
uint8   FS_GetDateTime(SYS_TIME *CurTime); 
/********************************************************************************************************* 
** 函数名称: FileInit 
** 功能描述: 初始化文件指针系统 
** 
** 输 入: 无 
** 
** 输 出: 无 
**          
** 全局变量: 无 
** 调用模块: 无 
** 
** 作 者: 陈明计 
** 日 期: 2003年6月5日 
**------------------------------------------------------------------------------------------------------- 
** 修改人: 
** 日 期: 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
        void FileInit(void) 
{ 
    HANDLE i; 
     
    for (i = 0; i < MAX_OPEN_FILES; i++) 
    { 
        FileInfo[i].Flags = 0; 
    } 
} 
 
/********************************************************************************************************* 
** 函数名称: FindOpenFile 
** 功能描述: 查找已打开的指定文件的文件句柄,内部使用 
** 
** 输 入: Drive:文件所在的逻辑盘号 
**        DirClus:文件所在目录的开始簇号 
**        FileName:内部文件名 
** 输 出: 文件句柄,Not_Open_FILE为没有打开 
**          
** 全局变量: FileInfo 
** 调用模块: _GetFDTInfo,GetDrive,FindFDTInfo, 
** 
** 作 者: 陈明计 
** 日 期: 2003年6月5日 
**------------------------------------------------------------------------------------------------------- 
** 修改人: 
** 日 期: 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
        HANDLE FindOpenFile(uint8 Drive, uint32 DirClus, char FileName[11]) 
{ 
    HANDLE Rt; 
    MY_FILE *fp; 
     
    fp = FileInfo; 
    for (Rt = 0; Rt < MAX_OPEN_FILES; Rt++) 
    { 
        if (fp->Flags != 0) 
        if (fp->Drive == Drive) 
        if (fp->DirClus == DirClus) 
        if (fp->Name[0] == FileName[0]) 
        if (fp->Name[1] == FileName[1]) 
        if (fp->Name[2] == FileName[2]) 
        if (fp->Name[3] == FileName[3]) 
        if (fp->Name[4] == FileName[4]) 
        if (fp->Name[5] == FileName[5]) 
        if (fp->Name[6] == FileName[6]) 
        if (fp->Name[7] == FileName[7]) 
        if (fp->Name[8] == FileName[8]) 
        if (fp->Name[9] == FileName[9]) 
        if (fp->Name[10] == FileName[10]) 
        { 
            break; 
        } 
        fp++; 
    } 
    if (Rt >= MAX_OPEN_FILES) 
    { 
        Rt = Not_Open_FILE; 
    } 
    return Rt; 
} 
 
/********************************************************************************************************* 
** 函数名称: RemoveFile 
** 功能描述: 删除文件 
** 
** 输 入: DirFileName:用户使用的文件名 
** 
** 输 出: RETURN_OK:成功 
**        其它参考fat.h中关于返回值的说明 
** 全局变量: 无 
** 调用模块: strupr,_GetFDTInfo,GetDrive,FindFDTInfo,FATDelClusChain,DelFDT 
** 
** 作 者: 陈明计 
** 日 期: 2003年6月5日 
**------------------------------------------------------------------------------------------------------- 
** 修改人: 陈明计 
** 日 期: 2004年4月10日 
**------------------------------------------------------------------------------------------------------ 
 
 
 
********************************************************************************************************/ 
        uint8 RemoveFile(char *DirFileName) 
{ 
    uint32 ClusIndex, ClusIndex1; 
    uint8 Drive, Rt; 
    char DirName[12]; 
    FDT temp; 
    uint8 tmp; 
     
    DirFileName = FsStrCopy(DirFileName); 
    strupr(DirFileName);                       /* 变为大写 */ 
    ClusIndex = _GetFDTInfo(DirName, DirFileName); 
    Rt = PATH_NOT_FIND; 
    if (ClusIndex != BAD_CLUS) 
    { 
        Drive = GetDrive(DirFileName);     /* 获取文件所在逻辑盘号 */ 
        Rt = FindFDTInfo(&temp, Drive, ClusIndex, DirName); 
        if (Rt == RETURN_OK) 
        { 
            Rt = NOT_FIND_FILE; 
            if ((temp.Attr & ATTR_DIRECTORY) == 0)  /* 是文件才删除 */ 
            { 
                Rt = FILE_LOCK; 
                tmp = FindOpenFile(Drive, ClusIndex, DirName); 
                if (tmp >= MAX_OPEN_FILES) 
                { 
                    /* 文件没有打开才删除 */ 
                    ClusIndex1 = temp.FstClusLO + ((uint32)(temp.FstClusHI) << 16); 
                    FATDelClusChain(Drive, ClusIndex1); 
                    Rt = DelFDT(Drive, ClusIndex, DirName); 
                } 
            } 
        } 
    } 
    return Rt; 
} 
 
/********************************************************************************************************* 
** 函数名称: FindOpenFileW 
** 功能描述: 查找以读写方式打开的指定文件的文件句柄,内部使用 
** 
** 输 入: Drive:文件所在的逻辑盘号 
**        DirClus:文件所在目录的开始簇号 
**        FileName:内部文件名 
** 输 出: 文件句柄,Not_Open_FILE为没有打开 
**          
** 全局变量: FileInfo 
** 调用模块: _GetFDTInfo,GetDrive,FindFDTInfo, 
** 
** 作 者: 陈明计 
** 日 期: 2003年6月5日 
**------------------------------------------------------------------------------------------------------- 
** 修改人: 
** 日 期: 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
        HANDLE FindOpenFileW(uint8 Drive, uint32 DirClus, char FileName[11]) 
{ 
    HANDLE Rt; 
    MY_FILE *fp; 
     
    fp = FileInfo; 
    for (Rt = 0; Rt < MAX_OPEN_FILES; Rt++) 
    { 
        if ((fp->Flags & FILE_FLAGS_WRITE) != 0) 
        if (fp->Drive == Drive) 
        if (fp->DirClus == DirClus) 
        if (fp->Name[0] == FileName[0]) 
        if (fp->Name[1] == FileName[1]) 
        if (fp->Name[2] == FileName[2]) 
        if (fp->Name[3] == FileName[3]) 
        if (fp->Name[4] == FileName[4]) 
        if (fp->Name[5] == FileName[5]) 
        if (fp->Name[6] == FileName[6]) 
        if (fp->Name[7] == FileName[7]) 
        if (fp->Name[8] == FileName[8]) 
        if (fp->Name[9] == FileName[9]) 
        if (fp->Name[10] == FileName[10]) 
        { 
            break; 
        } 
        fp++; 
    } 
    if (Rt >= MAX_OPEN_FILES) 
    { 
        Rt = Not_Open_FILE; 
    } 
    return Rt; 
} 
 
/********************************************************************************************************* 
** 函数名称: _FileOpenR 
** 功能描述: 只读方式打开文件,内部使用 
** 
** 输 入: DirFileName:用户使用的文件名 
** 
** 输 出: 文件句柄,Not_Open_FILE为不能打开 
**          
** 全局变量: FileInfo 
** 调用模块: _GetFDTInfo,GetDrive,FindFDTInfo, 
** 
** 作 者: 陈明计 
** 日 期: 2003年6月5日 
**------------------------------------------------------------------------------------------------------- 
** 修改人: 陈明计 
** 日 期: 2004年4月10日 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
        HANDLE _FileOpenR(char *DirFileName) 
{ 
    MY_FILE *fp; 
    HANDLE Rt; 
    FDT FileFDT; 
     
    /* 查找空闲文件登记项 */ 
    for (Rt = 0; Rt < MAX_OPEN_FILES; Rt++) 
    { 
        if (FileInfo[Rt].Flags == 0) 
        { 
            break; 
        } 
    } 
     
    if (Rt < MAX_OPEN_FILES) 
    { 
        fp = FileInfo + Rt; 
         
        /* 获取目录开始簇号和文件名 */ 
        fp->DirClus = _GetFDTInfo(fp->Name, DirFileName); 
        if (fp->DirClus < BAD_CLUS) 
        { 
            fp->Drive = GetDrive(DirFileName);     /* 获取文件所在逻辑盘号 */ 
             
            /* 获取文件信息 */ 
            if (FindFDTInfo(&FileFDT, fp->Drive, fp->DirClus, fp->Name) == RETURN_OK) 
            { 
                if ((FileFDT.Attr & ATTR_DIRECTORY) == 0) 
                { 
                    fp->Flags = FILE_FLAGS_READ; 
                    fp->FileSize = FileFDT.FileSize; 
                    fp->FstClus = FileFDT.FstClusLO | (uint32)FileFDT.FstClusHI << 16; 
                    fp->Clus = fp->FstClus; 
                    fp->Offset = 0; 
                    return Rt; 
                } 
            } 
        } 
    } 
    return Not_Open_FILE; 
} 
 
/********************************************************************************************************* 
** 函数名称: _FileOpenW 
** 功能描述: 只写方式打开文件,内部使用 
** 
** 输 入: DirFileName:用户使用的文件名 
** 
** 输 出: 文件句柄,Not_Open_FILE为不能打开 
**          
** 全局变量: FileInfo 
** 调用模块: _GetFDTInfo,GetDrive,FindFDTInfo, 
** 
** 作 者: 陈明计 
** 日 期: 2003年6月5日 
**------------------------------------------------------------------------------------------------------- 
** 修改人: 严寒亮 
** 日 期: 2004年11月5日 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
	HANDLE _FileOpenW(char *DirFileName) 
{ 
    MY_FILE *fp; 
    FDT temp; 
    HANDLE Rt; 
    uint8 i; 
    SYS_TIME CurTime,CrtTime;	// 保存当前时间日期  yhl 
 
    for (Rt = 0; Rt < MAX_OPEN_FILES; Rt++)	// 获取空闲的登记项 
    { 
        if (FileInfo[Rt].Flags == 0) 
        { 
            break; 
        } 
    } 
     
    if (Rt < MAX_OPEN_FILES) 
    { 
        fp = FileInfo + Rt;					// 指向获得的空闲登记项 
         
        /* 获取目录开始簇号和文件名 */ 
        fp->DirClus = _GetFDTInfo(fp->Name, DirFileName);	// 获取该文件的FDT项的首簇号,及文件名 
        if (fp->DirClus < BAD_CLUS) 
        { 
            fp->Drive = GetDrive(DirFileName);     /* 获取文件所在逻辑盘号 */ 
 
            /* 文件已经以读写方式打开,不能再次以读写方式打开 */ 
            if (FindOpenFileW(fp->Drive, fp->DirClus, fp->Name) == Not_Open_FILE) 
            { 
                if(FS_GetDateTime(&CurTime) != RETURN_OK) // 获取当前系统时间 
                { 
                	return GET_TIME_ERR; 
                } 
                 
                if (FindFDTInfo(&temp, fp->Drive, fp->DirClus, fp->Name) == RETURN_OK) 
                { 
                    if ((temp.Attr & ATTR_DIRECTORY) != 0) 
                    { 
                       return Not_Open_FILE;		// 如果该文件为目录,则不能删除 
                    } 
                     
                    CrtTime.date = temp.CrtDate;    // 保存文件建立时间 
                    CrtTime.time = temp.CrtTime; 
                    CrtTime.msec = temp.CrtTimeTenth; 
                     
                    if (RemoveFile(DirFileName) != RETURN_OK)   /* 删除文件 */ 
                    { 
                       return Not_Open_FILE; 
                    } 
                } 
                else 
                { 
                    CrtTime = CurTime;              // 设置文件建立时间为当前时间 
                }                 
                 
                /* 创建文件 */ 
                for (i = 0; i < 11; i++)			// 创建将要生成文件的FDT项 
                { 
                    temp.Name[i] = fp->Name[i];		// 复制名字 
                } 
                temp.Attr = 0;						// 特性为0 
                temp.FileSize = 0; 
 
                temp.NTRes = 0; 
                 
                /*-------在此加入创建时间的程序---------*/ 
                temp.CrtTimeTenth = CrtTime.msec;	 
                temp.CrtTime = CrtTime.time; 
                temp.CrtDate = CrtTime.date; 
                 
                temp.LstAccDate = CurTime.date; 
                temp.WrtTime = CurTime.time + 1; 
                temp.WrtDate = CurTime.date; 
				/*--------------------------------------*/ 
				 
                temp.FstClusLO = 0; 
                temp.FstClusHI = 0; 
                if (AddFDT(fp->Drive, fp->DirClus, &temp) == RETURN_OK)       /* 增加文件 */ 
                { 
                    /* 设置文件信息 */ 
                    fp->Flags = FILE_FLAGS_READ | FILE_FLAGS_WRITE; 
                    fp->FileSize = 0; 
                    fp->FstClus = 0; 
                    fp->Clus = 0; 
                    fp->Offset = 0; 
                    return Rt; 
                } // if(Add..) 
            } // if(Find..) 
        } // if(fp..) 
    } // if(Rt..) 
    return Not_Open_FILE; 
} 
 
/********************************************************************************************************* 
** 函数名称: _FileOpenRW 
** 功能描述: 只读写方式打开文件,内部使用 
** 
** 输 入: DirFileName:用户使用的文件名 
** 
** 输 出: 文件句柄,Not_Open_FILE为不能打开 
**          
** 全局变量: 无 
** 调用模块: _FileOpenR,_FileOpenW 
** 
** 作 者: 陈明计 
** 日 期: 2003年6月5日 
**------------------------------------------------------------------------------------------------------- 
** 修改人: 
** 日 期: 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
        HANDLE _FileOpenRW(char *DirFileName) 
{ 
    HANDLE Rt; 
     
    Rt = _FileOpenR(DirFileName); 
    if (Rt == Not_Open_FILE) 
    { 
        Rt = _FileOpenW(DirFileName); 
    } 
    else 
    { 
        if (FindOpenFileW(FileInfo[Rt].Drive, FileInfo[Rt].DirClus, FileInfo[Rt].Name) == Not_Open_FILE) 
        { 
            FileInfo[Rt].Flags |=  (FILE_FLAGS_WRITE | FILE_FLAGS_READ); 
        } 
        else 
        { 
            FileInfo[Rt].Flags = 0; 
            Rt = Not_Open_FILE; 
        } 
    } 
    return Rt; 
} 
 
/********************************************************************************************************* 
** 函数名称: FileOpen 
** 功能描述: 以指定方式打开文件 
** 
** 输 入: DirFileName:用户使用的文件名 
**        Type:打开方式 
** 输 出: 文件句柄,Not_Open_FILE为不能打开 
**          
** 全局变量: 无 
** 调用模块: _FileOpenR,_FileOpenW,_FileOpenRW 
** 
** 作 者: 陈明计 
** 日 期: 2003年6月5日 
**------------------------------------------------------------------------------------------------------- 
** 修改人: 
** 日 期: 
**------------------------------------------------------------------------------------------------------ 
 
 
 
********************************************************************************************************/ 
        HANDLE FileOpen(char *DirFileName, char *Type) 
{ 
    HANDLE Rt; 
 
    Rt = Not_Open_FILE;     
    Type = FsStrCopy(Type); 
    strupr(Type); 
    if (Type[0] == 'R') 
    { 
        if (Type[1] == 'W') 
        { 
            DirFileName = FsStrCopy(DirFileName); 
            strupr(DirFileName); 
            Rt = _FileOpenRW(DirFileName); 
        } 
        else 
        { 
            DirFileName = FsStrCopy(DirFileName); 
            strupr(DirFileName); 
            Rt = _FileOpenR(DirFileName); 
        } 
        return Rt; 
    } 
    if (Type[0] == 'W') 
    { 
        if (Type[1] == 'R') 
        { 
            DirFileName = FsStrCopy(DirFileName); 
            strupr(DirFileName); 
            Rt = _FileOpenRW(DirFileName); 
        } 
        else 
        { 
            DirFileName = FsStrCopy(DirFileName); 
            strupr(DirFileName); 
            Rt = _FileOpenW(DirFileName); 
        } 
    } 
    return Rt; 
} 
 
/********************************************************************************************************* 
** 函数名称: FileClose 
** 功能描述: 关闭指定文件 
** 
** 输 入: Handle:文件句柄 
** 
** 输 出: RETURN_OK:成功 
**        其它参考fat.h中关于返回值的说明  
** 全局变量: 无 
** 调用模块: 无 
** 
** 作 者: 陈明计 
** 日 期: 2003年6月5日 
**------------------------------------------------------------------------------------------------------- 
** 修改人: 严寒亮        
** 日 期: 2004年11月5日 
** 说  明: 增加文件的最后访问时间属性和最后修改时间属性 
**------------------------------------------------------------------------------------------------------ 
** 流  程: 判断文件是否有写状态-Y->取出该文件FDT项-->判断文件大小是否变化-Y->更新FDT中首簇号-->保存FDT项 
** 注  意: 关闭文件后,将释放其登记项,并把修改过的扇区回写保存,但其仍占用原来的cache。 
********************************************************************************************************/ 
        uint8 FileClose(HANDLE Handle) 
{ 
    uint8 Rt; 
    FDT FileFDT; 
    MY_FILE *fp; 
    SYS_TIME CurTime; 
     
    Rt = PARAMETER_ERR; 
    if (Handle < MAX_OPEN_FILES) 
    { 
        if(FS_GetDateTime(&CurTime) != RETURN_OK)       // 获取当前时间 
        { 
            return GET_TIME_ERR; 
        } 
                                                         
        fp = FileInfo + Handle;		                    // 获取该文件的FDT项 
        Rt = FindFDTInfo(&FileFDT, fp->Drive, fp->DirClus, fp->Name); 
        if (Rt != RETURN_OK) 
        { 
            return Rt; 
        } 
         
        FileFDT.LstAccDate = CurTime.date;              // 更新文件最后访问时间 
                                                        // 如果文件不是以只写方式打开就不需要保存 
        if ((fp->Flags & FILE_FLAGS_WRITE) == FILE_FLAGS_WRITE)	 
        { 
            if (FileFDT.FileSize < fp->FileSize)		// 查看文件大小是否发生变化 
            { 
                FileFDT.FileSize = fp->FileSize;	 
                                                        // 更新文件最后修改时间 
                FileFDT.WrtTime = CurTime.time + 1;     // 修改时间需要加2秒,因为它不能计算到毫秒戳 
                FileFDT.WrtDate = CurTime.date; 
                 
                if (FileFDT.FstClusLO == 0) 
                if (FileFDT.FstClusHI == 0) 
                { 
                    FileFDT.FstClusLO = fp->FstClus & 0xffff; 
                    FileFDT.FstClusHI = (fp->FstClus >> 16) & 0xffff; 
                } 
            } 
        } 
        ChangeFDT(fp->Drive, fp->DirClus, &FileFDT);	// 将修改后的FDT项保存 
        fp->Flags = 0; 
    } 
    return Rt; 
} 
 
/********************************************************************************************************* 
** 函数名称: FileGetCh 
** 功能描述: 从文件读一个字节 
** 
** 输 入: Ch:返回读到的数据 
**        Handle:文件句柄 
** 输 出: RETURN_OK:成功 
**        其它参考fat.h中关于返回值的说明  
** 全局变量: 无 
** 调用模块: 无 
** 
** 作 者: 陈明计 
** 日 期: 2003年6月5日 
**------------------------------------------------------------------------------------------------------- 
** 修改人: 陈明计 
** 日 期: 2004年4月10日 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
        uint8 FileGetCh(uint8 *Ch, HANDLE Handle) 
{ 
    uint32 i, j, SecIndex; 
    MY_FILE *fp; 
    Disk_Info * DiskInfo; 
    uint8 Rt; 
    uint8 *Buf; 
     
    Rt = PARAMETER_ERR; 
    fp = FileInfo + Handle; 
    if (Handle < MAX_OPEN_FILES)     /* Handle是否有效 */ 
    if (fp->Flags != 0)                             /* 对应的打开文件信息表是否已使用 */ 
    { 
        Rt = FILE_EOF; 
        if (fp->Offset >= fp->FileSize) 
        { 
            /* 如果读数据超出文件的长度,看一看谁否有别的程序正在写这个文件 */ 
            /* 如果有,则可能文件的长度有变化,更正之*/ 
            Handle = FindOpenFileW(fp->Drive, fp->DirClus, fp->Name); 
            if (Handle < MAX_OPEN_FILES) 
            { 
                fp->FileSize = FileInfo[Handle].FileSize; 
                if (fp->Offset == 0) 
                { 
                    fp->FstClus = FileInfo[Handle].FstClus; 
                    fp->Clus = fp->FstClus; 
                } 
            } 
        } 
        Rt = FILE_EOF; 
        if (fp->Offset < fp->FileSize)              /* 是否到文件结束 */ 
        { 
            Rt = NOT_FIND_DISK; 
                /* 获取文件所在逻辑盘信息 */ 
            DiskInfo = GetDiskInfo(fp->Drive); 
            if (DiskInfo != NULL) 
            { 
                /* 计算数据所在扇区 */ 
                j = fp->Offset % (DiskInfo->SecPerClus * DiskInfo->BytsPerSec); 
                i = j / DiskInfo->BytsPerSec; 
                j = j % DiskInfo->BytsPerSec; 
                SecIndex = (fp->Clus - 2) * DiskInfo->SecPerClus +  
                           DiskInfo->DataStartSec + i; 
                Rt = SECTOR_READ_ERR; 
                /* 打开扇区 */ 
                Buf = OpenSec(fp->Drive, SecIndex); 
                if (Buf != NULL) 
                { 
                    /* 读取扇区数据 */ 
                    if (ReadSec(fp->Drive, SecIndex) == RETURN_OK) 
                    { 
                        /* 读取数据 */ 
                        *Ch = Buf[j]; 
                        /* 调整文件指针 */ 
                        fp->Offset++; 
                        j++; 
                        if (j >= DiskInfo->BytsPerSec) 
                        { 
                            i++; 
                            if (i >= DiskInfo->SecPerClus) 
                            { 
                                fp->Clus = FATGetNextClus(fp->Drive, fp->Clus); 
                            } 
                        } 
                        Rt = RETURN_OK; 
                    } 
                    /* 关闭扇区 */ 
                    CloseSec(fp->Drive, SecIndex); 
                } 
            } 
        } 
    } 
    return Rt; 
} 
 
/********************************************************************************************************* 
** 函数名称: FileRead 
** 功能描述: 读取文件 
** 
** 输 入: Buf:保存读回的数据 
**        Size:要读的字节数 
**        Handle:文件句柄 
** 输 出: 实际读到的字节数 
**          
** 全局变量: 无 
** 调用模块: 无 
** 
** 作 者: 陈明计 
** 日 期: 2003年6月5日 
**------------------------------------------------------------------------------------------------------- 
** 修改人: 
** 日 期: 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
        uint32 FileRead(void *Buf, uint32 Size, HANDLE Handle) 
{ 
    uint32 i, j, k, SecIndex; 
    MY_FILE *fp; 
    Disk_Info * DiskInfo; 
    uint32 Rt; 
    uint8 *Buf1, *Buf2; 
     
    Rt = 0; 
    fp = FileInfo + Handle; 
    Buf2 = (uint8 *)Buf; 
    if (Handle < MAX_OPEN_FILES)     /* Handle是否有效 */ 
    if (fp->Flags != 0)                             /* 对应的打开文件信息表是否已使用 */ 
    { 
        if (fp->Offset + Size >= fp->FileSize) 
        { 
            /* 如果读数据超出文件的长度,看一看谁否有别的程序正在写这个文件 */ 
            /* 如果有,则可能文件的长度有变化,更正之*/ 
            Handle = FindOpenFileW(fp->Drive, fp->DirClus, fp->Name); 
            if (Handle < MAX_OPEN_FILES) 
            { 
                fp->FileSize = FileInfo[Handle].FileSize; 
                if (fp->Offset == 0) 
                { 
                    fp->FstClus = FileInfo[Handle].FstClus; 
                    fp->Clus = fp->FstClus; 
                } 
            } 
        } 
 
        while (Size != 0) 
        { 
            if (fp->Offset >= fp->FileSize)              /* 是否到文件结束 */ 
            { 
                break; 
            } 
            /* 获取文件所在逻辑盘信息 */ 
            DiskInfo = GetDiskInfo(fp->Drive); 
            if (DiskInfo == NULL) 
            { 
                break; 
            } 
            /* 计算数据所在扇区 */ 
            j = fp->Offset % (DiskInfo->SecPerClus * DiskInfo->BytsPerSec); 
            i = j / DiskInfo->BytsPerSec; 
            j = j % DiskInfo->BytsPerSec; 
            SecIndex = (fp->Clus - 2) * DiskInfo->SecPerClus +  
                       DiskInfo->DataStartSec + i; 
            /* 打开扇区 */ 
            Buf1 = OpenSec(fp->Drive, SecIndex); 
            if (Buf1 == NULL) 
            { 
                break; 
            } 
            /* 读取扇区数据 */ 
            if (ReadSec(fp->Drive, SecIndex) != RETURN_OK) 
            { 
                break; 
            } 
            /* 读取数据 */ 
            k = DiskInfo->BytsPerSec - j; 
            if (Size < k) 
            { 
                k = Size; 
            } 
            if ((fp->Offset + k) > fp->FileSize) 
            { 
                k = fp->FileSize - fp->Offset; 
            } 
            Size -= k; 
            Rt += k; 
            fp->Offset += k; 
 
            memcpy(Buf2, Buf1 + j, k); 
            Buf2 += k; 
 
            /* 关闭扇区 */ 
            CloseSec(fp->Drive, SecIndex); 
            j += k;     
            if (j >= DiskInfo->BytsPerSec) 
            { 
                i++; 
                if (i >= DiskInfo->SecPerClus) 
                { 
                    fp->Clus = FATGetNextClus(fp->Drive, fp->Clus); 
                } 
            } 
        } 
    } 
    return Rt; 
} 
 
/********************************************************************************************************* 
** 函数名称: FilePutCh 
** 功能描述: 写一个字节到文件 
** 
** 输 入: Ch:要写的数据 
**        Handle:文件句柄 
** 输 出: RETURN_OK:成功 
**        其它参考fat.h中关于返回值的说明  
** 全局变量: 无 
** 调用模块: 无 
** 
** 作 者: 陈明计 
** 日 期: 2003年6月5日 
**------------------------------------------------------------------------------------------------------- 
** 修改人: 陈明计 
** 日 期: 2004年4月10日 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
        uint8 FilePutCh(uint8 Ch, HANDLE Handle) 
{ 
    uint32 i, j, SecIndex; 
    MY_FILE *fp; 
    Disk_Info * DiskInfo; 
    uint8 Rt; 
    uint8 *Buf; 
 
    Rt = PARAMETER_ERR; 
    fp = FileInfo + Handle; 
    if (Handle < MAX_OPEN_FILES)      /* Handle是否有效 */ 
    if (((fp->Flags) & FILE_FLAGS_WRITE) != 0)       /* 文件是否可写 */ 
    { 
        Rt = FILE_EOF; 
        if (fp->Offset <= fp->FileSize) 
        { 
            Rt = NOT_FIND_DISK; 
                /* 获取文件所在逻辑盘信息 */ 
            DiskInfo = GetDiskInfo(fp->Drive); 
            if (DiskInfo != NULL) 
            { 
                j = (fp->Offset) % (DiskInfo->SecPerClus * DiskInfo->BytsPerSec); 
                 
                if (j == 0) 
                if (fp->Offset == fp->FileSize) 
                { 
                    i = FATAddClus(fp->Drive, fp->Clus); 
                    if (i >= BAD_CLUS) 
                    { 
                        return DISK_FULL; 
                    } 
                    fp->Clus = i; 
                    if (fp->FstClus == EMPTY_CLUS) 
                    { 
                        fp->FstClus = i; 
                    } 
                } 
                /* 计算数据所在扇区 */ 
                i = j / DiskInfo->BytsPerSec; 
                j = j % DiskInfo->BytsPerSec; 
                SecIndex = (fp->Clus - 2) * DiskInfo->SecPerClus + DiskInfo->DataStartSec + i; 
                Rt = SECTOR_READ_ERR; 
                 
                /* 打开扇区 */ 
                Buf = OpenSec(fp->Drive, SecIndex); 
                if (Buf != NULL) 
                { 
                    /* 写扇区数据 */ 
                    if (ReadSec(fp->Drive, SecIndex) == RETURN_OK) 
                    { 
                        /* 存储数据 */ 
                        Buf[j] = Ch; 
                        WriteSec(fp->Drive, SecIndex); 
                        Rt = RETURN_OK; 
                    } 
                    CloseSec(fp->Drive, SecIndex); 
                } 
 
                /* 调整打开文件信息表 */ 
                fp->Offset++; 
                if (fp->Offset > fp->FileSize) 
                { 
                    fp->FileSize = fp->Offset; 
                } 
 
                if ((j + 1) >= DiskInfo->BytsPerSec) 
                { 
                    if ((i + 1) >= DiskInfo->SecPerClus) 
                    if (fp->Offset < fp->FileSize) 
                    { 
                        fp->Clus = FATGetNextClus(fp->Drive, fp->Clus); 
                    } 
                }             
            } 
        } 
    } 
    return Rt; 
} 
 
/********************************************************************************************************* 
** 函数名称: FileWrite 
** 功能描述: 写文件 
** 
** 输 入: Buf:要写的数据 
**        Size:要写的字节数 
**        Handle:文件句柄 
** 输 出: 实际写的字节数 
**          
** 全局变量: 无 
** 调用模块: 无 
** 
** 作 者: 陈明计 
** 日 期: 2003年6月5日 
**------------------------------------------------------------------------------------------------------- 
** 修改人: 
** 日 期: 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
        uint32 FileWrite(void *Buf, uint32 Size, HANDLE Handle) 
{ 
    uint32 i, j, k, SecIndex; 
    MY_FILE *fp; 
    Disk_Info * DiskInfo; 
    uint32 Rt; 
    uint8 *Buf1, *Buf2; 
 
    if (Size == 0) 
    { 
        return 0; 
    } 
     
    Rt = 0; 
    fp = FileInfo + Handle;             // 获得登记项句柄 
    Buf2 = (uint8 *)Buf;                // 数据源 
    if (Handle < MAX_OPEN_FILES)        /* Handle是否有效 */ 
    if (((fp->Flags) & FILE_FLAGS_WRITE) != 0)       /* 文件是否可写 */ 
    { 
        if (fp->Offset > fp->FileSize)  // 偏移超出文件范围,返回 
        { 
            return 0; 
        } 
         
        while (Size != 0) 
        { 
            /* 获取文件所在逻辑盘信息 */ 
            DiskInfo = GetDiskInfo(fp->Drive); 
            if (DiskInfo == NULL) 
            { 
                break; 
            } 
            /* 计算数据所在扇区 */ 
            j = fp->Offset % (DiskInfo->SecPerClus * DiskInfo->BytsPerSec);   // 字节偏移量(簇内) 
             
            if (j == 0)  
            if (fp->Offset == fp->FileSize)   
            {           // 如果指向簇的最后一字节,并且偏移量等于文件大小,即指向文件最后一个字节 
                i = FATAddClus(fp->Drive, fp->Clus);  // 则需要增加新簇 
                if (i >= BAD_CLUS) 
                { 
                    return DISK_FULL; 
                } 
                fp->Clus = i; 
                if (fp->FstClus == EMPTY_CLUS) 
                { 
                    fp->FstClus = i; 
                } 
            } 
 
            i = j / DiskInfo->BytsPerSec;   // 扇区偏移(簇内) 
            j = j % DiskInfo->BytsPerSec;   // 字节偏移(扇区内) 
            SecIndex = (fp->Clus - 2) * DiskInfo->SecPerClus +  
                       DiskInfo->DataStartSec + i; 
 
            k = DiskInfo->BytsPerSec - j;   // 扇区剩余字节 
            if (Size < k)                   // 如果该扇区的空闲字节大于要保存的文件大小 
            { 
                k = Size; 
            } 
 
            /* 打开扇区 */ 
            Buf1 = OpenSec(fp->Drive, SecIndex); 
            if (Buf1 == NULL) 
            { 
                break; 
            } 
            /* 读取扇区数据 */ 
            if (ReadSec(fp->Drive, SecIndex) != RETURN_OK) 
            { 
                break; 
            } 
 
            memcpy(Buf1 + j, Buf2, k);      // 数据复制,从数据源Buf2复制K字节数据到Buf1+j 
            Buf2 += k;                      // 数据源指针加K 
 
            /* 关闭扇区 */ 
            WriteSec(fp->Drive, SecIndex);  // 设置被修改标记 
            CloseSec(fp->Drive, SecIndex); 
             
            Size -= k;                      // 剩余待写入数据量减k 
            Rt += k; 
            /* 调整文件指针 */ 
            fp->Offset += k;                // 写入点指针偏移位置+k 
            if (fp->Offset > fp->FileSize)  // 如果文件增大,更新文件大小值 
            { 
                fp->FileSize = fp->Offset; 
            } 
 
            if ((j + k) >= DiskInfo->BytsPerSec) 
            { 
                if ((i + 1) >= DiskInfo->SecPerClus) 
                if (fp->Offset < fp->FileSize) 
                { 
                    fp->Clus = FATGetNextClus(fp->Drive, fp->Clus); 
                } 
            } 
        } 
    } 
    return Rt; 
} 
 
/********************************************************************************************************* 
** 函数名称: FileCloseAll 
** 功能描述: 关闭所有打开的文件 
** 
** 输 入: 无 
** 
** 输 出: 无 
**          
** 全局变量: FileInfo 
** 调用模块: AllCacheWriteBack 
** 
** 作 者: 陈明计 
** 日 期: 2003年6月5日 
**------------------------------------------------------------------------------------------------------- 
** 修改人: 
** 日 期: 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
        void FileCloseAll(void) 
{ 
    uint32 i; 
 
    for (i = 0; i < MAX_OPEN_FILES; i++) 
    { 
        FileClose(i); 
    } 
    AllCacheWriteBack(); 
} 
 
/********************************************************************************************************* 
** 函数名称: FileEof 
** 功能描述: 判断文件是否到读\写到文件尾 
** 
** 输 入: Handle:文件句柄 
** 
** 输 出: 0:否 
**        1:是  
** 全局变量: FileInfo 
** 调用模块: 无 
** 
** 作 者: 陈明计 
** 日 期: 2003年6月5日 
**------------------------------------------------------------------------------------------------------- 
** 修改人: 
** 日 期: 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
        uint8 FileEof(HANDLE Handle) 
{ 
    if (Handle < MAX_OPEN_FILES) 
    if (FileInfo[Handle].Offset < FileInfo[Handle].FileSize) 
    { 
        return 0; 
    } 
    return 1; 
} 
 
/********************************************************************************************************* 
** 函数名称: FileSeek 
** 功能描述: 移动文件读\写位置 
** 
** 输 入: Handle:文件句柄 
**        offset:移动偏移量 
**        Whence:移动模式SEEK_SET:从文件头计算SEEK_CUR:从当前位置计算SEEK_END:从文件尾计算 
** 输 出: 无 
**          
** 全局变量: 无 
** 调用模块: 无 
** 
** 作 者: 陈明计 
** 日 期: 2003年6月5日 
**------------------------------------------------------------------------------------------------------- 
** 修改人: 陈明计 
** 日 期: 2004年4月10日 
**------------------------------------------------------------------------------------------------------ 
** 修改人: 陈明计 
** 日 期: 2004年7月12日 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
        uint8 FileSeek(HANDLE Handle, int32 offset, uint8 Whence) 
{ 
    uint8 Rt; 
    uint32 i, Clus; 
    MY_FILE *fp; 
    Disk_Info * DiskInfo; 
     
    Rt = PARAMETER_ERR; 
    fp = FileInfo + Handle; 
    if (Handle < MAX_OPEN_FILES)                    /* Handle是否有效 */ 
    if (fp->Flags  != 0)                            /* 对应的打开文件信息表是否已使用 */ 
    { 
        Rt = RETURN_OK; 
        switch (Whence) 
        { 
            case SEEK_END:             /* 从文件尾计算 */ 
                fp->Offset = fp->FileSize - offset; 
                offset = -offset; 
                break; 
            case SEEK_SET: 
                fp->Offset = offset; 
                break; 
            case SEEK_CUR:             /* 从当前位置计算 这里不用break是正确的*/ 
                i = fp->Offset + offset; 
                break; 
            default: 
                Rt = PARAMETER_ERR; 
                break; 
        } 
        /* 改变当前簇号 */ 
        if (Rt == RETURN_OK) 
        { 
            if (fp->Offset > fp->FileSize) 
            { 
                if (offset > 0) 
                { 
                    fp->Offset = fp->FileSize; 
                } 
                else 
                { 
                    fp->Offset = 0; 
                } 
            } 
            Rt = NOT_FIND_DISK; 
            DiskInfo = GetDiskInfo(fp->Drive); 
            if (DiskInfo != NULL) 
            { 
                Rt = RETURN_OK; 
                i = fp->Offset / (DiskInfo->BytsPerSec * DiskInfo->SecPerClus); 
                Clus = fp->FstClus; 
                for (; i != 0; i--) 
                { 
                    Clus = FATGetNextClus(fp->Drive, Clus); 
                    if (Clus >= BAD_CLUS) 
                    { 
                        Rt = FAT_ERR; 
                        break; 
                    } 
                } 
                fp->Clus = Clus; 
            } 
        } 
    } 
    return Rt; 
} 
 
/********************************************************************************************************* 
** 函数名称: FS_GetDateTime 
** 功能描述: 时间格式转换函数,将DATE_TIME格式的数据转换为SYS_TIME格式的时间数据 
** 
** 输 入: CurTime  指向保存结果 
** 
** 输 出: 错误代码,RETURN_OK为正确 
**          
** 全局变量: 无 
** 调用模块: GetDataTime 
** 
** 作 者: 严寒亮 
** 日 期: 2004年11月3日 
**------------------------------------------------------------------------------------------------------- 
** 修改人: 
** 日 期: 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
   uint8   FS_GetDateTime(SYS_TIME *CurTime) 
{ 
   uint8       temp8; 
   uint16      temp16 = 0; 
   DATE_TIME   Time; 
    
   temp8 = GetDataTime(&Time);            // 获取当前时间 
   if(temp8 != RETURN_OK) 
   { 
      return temp8;                       // 如果获取失败,就返回错误代码 
   } 
    
   /* 时间格式转换 */ 
   if(Time.da_year > 1980) 
   { 
      temp16  = Time.da_year - 1980;      // 年,如果当前年小于1980年,设为0 
   } 
   temp16  = (temp16 & 0x7F) << 9;        // 年:9~15位 
   temp16 |= (Time.da_mon & 0x0F) << 5;   // 月:5~8位 
   temp16 |= Time.da_day & 0x1F ;         // 日:0~4位 
   CurTime->date = temp16; 
	 
   temp16  = (Time.ti_hour & 0x1F) << 11; // 时:11~15位 
   temp16 |= (Time.ti_min  & 0x3F) << 5;  // 分:5~10位 
   temp16 |= (Time.ti_sec  & 0x3F) >> 1;  // 秒,变为2秒的倍数:0~4位 
   CurTime->time = temp16;  
    
   if((Time.ti_sec & 0x01) == 0x01) 
   { 
      temp8   = 100;                   // 如果当前秒为奇数,毫秒戳加上100 
   }  
   temp8   += Time.ti_hund;            // 加上百分之一秒数 
   CurTime->msec = temp8; 
    
   return RETURN_OK; 
} 
 
/********************************************************************************************************* 
**                            End Of File 
********************************************************************************************************/