win32 CreateFile readFile writefile 文件读写

来源:互联网 发布:世界地图矢量数据 编辑:程序博客网 时间:2024/05/20 02:27
之前一直做Android和iOS开发,最近换了工作在Windows上做开发,需要实现个文档上传下载的库给小组使用,使用VS2010.之前一直没使用过VS,不过有C++基础,he网络传输的经验也不是什么难事。需求就是多任务文件上传下载,包括断点续传,管理等。于是乎就开始做呗,想多任务线程管理这里就不说了,来说说文件读与写吧。


之前在Java、和在Linux都使用过文件的读与写。其实不管是什么平台不外乎就是获取文件句柄,通过文件句柄进行读写,然后关闭句柄。就是这么简单,那么WIN32下是怎么样获取文件句柄呢?


查看API就有一个createFile()函数,原型如下:

HANDLE CreateFile(
 LPCTSTR lpFileName, // 要打开的文件名
 DWORD dwDesiredAccess, // 文件的操作属性
 DWORD dwShareMode, // 文件共享属性
 LPSECURITY_ATTRIBUTES lpSecurityAttributes,// 文件安全特性
 DWORD dwCreationDisposition, //文件操作
 DWORD dwFlagsAndAttributes, // 文件属性
 HANDLE hTemplateFile // 如果不为零,则指定一个文件句柄。新文件将从这个文件中复制扩展属性
);


借鉴与网络资料和书籍
文件的操作属性:如果为零,表示只允许获取与一个设备有关的信息,GENERIC_READ 表示允许对设备进行读访问;如果为 GENERIC_WRITE 表示允许对设备进行写访问(可组合使用);
  文件的共享属性:零表示不共享; FILE_SHARE_READ 或 FILE_SHARE_WRITE 表示允许对文件进行读/写共享访问;
  文件的操作有:
  ·CREATE_NEW:创建文件;如文件存在则会出错
  ·CREATE_ALWAYS:创建文件,会改写前一个文件
  ·OPEN_EXISTING:文件必须已经存在。由设备提出要求
  ·OPEN_ALWAYS:如文件不存在则创建它
  ·TRUNCATE_EXISTING:将现有文件缩短为零长度
  文件属性有:
  ·FILE_ATTRIBUTE_ARCHIVE:标记归档属性
  ·FILE_ATTRIBUTE_COMPRESSED:将文件标记为已压缩,或者标记为文件在目录中的默认压缩方式
  ·FILE_ATTRIBUTE_NORMAL:默认属性
  ·FILE_ATTRIBUTE_HIDDEN:隐藏文件或目录
  ·FILE_ATTRIBUTE_READONLY:文件为只读
  ·FILE_ATTRIBUTE_SYSTEM:文件为系统文件
  ·FILE_FLAG_WRITE_THROUGH:
 操作系统不得推迟对文件的写操作
  ·FILE_FLAG_OVERLAPPED:允许对文件进行重叠操作
  ·FILE_FLAG_NO_BUFFERING:禁止对文件进行缓冲处理。文件只能写入磁盘卷的扇区块
  ·FILE_FLAG_RANDOM_ACCESS:针对随机访问对文件缓冲进行优化
  ·FILE_FLAG_SEQUENTIAL_SCAN:针对连续访问对文件缓冲进行优化
  ·FILE_FLAG_DELETE_ON_CLOSE:关闭了上一次打开的句柄后,将文件删除。特别适合临时文件
  可以组合的属性有:FILE_FLAG_WRITE_THROUGH,FILE_FLAG_OVERLAPPED,FILE_FLAG_NO_BUFFERING,FILE_FLAG_RANDOM_ACCESS,FILE_FLAG_SEQUENTIAL_SCAN,FILE_FLAG_DELETE_ON_CLOSE,FILE_FLAG_BACKUP_SEMANTICS,FILE_FLAG_POSIX_SEMANTICS,FILE_FLAG_OPEN_REPARSE_POINT,FILE_FLAG_OPEN_NO_RECALL
  如果成功返回一个打开文件得句柄,如果调用函数之前文件存在,文件操作属性为:CREATE_ALWAYS 或 OPEN_ALWAYS,使用GetLastError函数返回的是ERROR_ALREADY_EXISTS(包括函数操作成功),如果之前函数不存在,则返回0。使用失败返回INVALID_HANDLE_VALUE,要取得更多的信息,使用GetLastError函数。
  文件关闭用:
BOOL CloseHandle(HANDLE hObject // handle to object to close);


函数WriteFile和ReadFile声明如下:
WINBASEAPI
BOOL
WINAPI
WriteFile(
    __in        HANDLE hFile,
    __in_bcount(nNumberOfBytesToWrite) LPCVOID lpBuffer,
    __in        DWORD nNumberOfBytesToWrite,
    __out_opt   LPDWORD lpNumberOfBytesWritten,
    __inout_opt LPOVERLAPPED lpOverlapped
    );
   
WINBASEAPI
BOOL
WINAPI
ReadFile(
    __in        HANDLE hFile,
    __out_bcount_part(nNumberOfBytesToRead, *lpNumberOfBytesRead) LPVOID lpBuffer,
    __in        DWORD nNumberOfBytesToRead,
    __out_opt   LPDWORD lpNumberOfBytesRead,
    __inout_opt LPOVERLAPPED lpOverlapped
    );
 
hFile是文件句柄。
lpBuffer是读写数据缓冲区。
nNumberOfBytesToWrite是多少数据要写入。
lpNumberOfBytesWritten是已经写入多少数据。
nNumberOfBytesToRead是多少数据要读取。
nNumberOfBytesToRead是已经读取多少数据。
lpOverlapped是异步读写的结构。

这些参数什么的真的太多了,具体不同需要还是要去认真看,这里不多介绍网上也很多这种资料。
这里要实现一个断点续传功能,也就是要在自己操控文件指针,指到断点位置,然后继续往下写或者读。

使用到函数WORD dwPtr = SetFilePointer(m_mFileHandle, Offset, NULL, FILE_BEGIN);
m_mFileHandle, 为你的文件句柄
Offset:文件指针位置。就是你上一次读取的位置。


代码如下

/*********************************************************** *  Name:DataTypeDefine.h *  Purpose: Define Data struct *  Author: zzf *  Created: 2016/03/21 *  Copyright: ut ************************************************************/#ifndef H_DATA_TYPE_DEFINE_H#define H_DATA_TYPE_DEFINE_H#define DEBUG_TYPE    //调试宏定义#include <string>#include <Windows.h>using namespace std;typedef signed long long     TSint64;typedef unsigned long longTUint64; struct S_TTransferTaskInfo{int m_nTaskType; // 0:上传,1:下载string m_strTaskID; // 传输任务IDstring m_strPath; // 如果是上传,则是文件的全路径,如果是下载,是文件的存放路径string m_strFileName; // 文件名string m_strUrl; // Url地址,上传时指远程的路径,下载时指下载文件的全路径TUint64 m_ulTotalSize; // 上传或者下载文件总长度TUint64 m_ulCurSize; // 上传,指已经上传成功的长度,下载,指已经下载的实际长度string m_strOriginalMD5; // 原始文件MD5S_TTransferTaskInfo(){m_nTaskType = 0;m_ulTotalSize = 0;m_ulCurSize = 0;        m_strTaskID = "TaskID";}};typedef enum NsResultEnum{RESULT_OK = 0,// 成功RESULT_UPLOAD_FAILED,   // 上传失败RESULT_DOWNLOAD_FAILED  // 下载失败};enum ETASK_WORK_TYPE{    UPLOAD_TYPE     = 0,    DOWNLOAD_TYPE   = 1};typedef void (*TaskExecuteCallBackFun)(HANDLE phandle,S_TTransferTaskInfo mTransferTaskInfo);typedef size_t (*OnWriteDataCallBackFun)(HANDLE phandle,void* buffer, size_t size, size_t nmemb, void* lpVoid);#endif


/*********************************************************** *  Name:CIniConfigfileManager.h *  Purpose: int file manager  *  Author: zzf *  Created: 2016/04/18 *  Copyright: ut ************************************************************/#ifndef H_CINICONFIGFILEMANAGER_H#define H_CINICONFIGFILEMANAGER_H#include "iconfigfile.h"#include "DataTypeDefine.h"#include <iostream>#include <vector>#include <stdio.h>using namespace std;class CIniConfigfileManager :    public IConfigFile{public:    CIniConfigfileManager(string sFilePath);    ~CIniConfigfileManager(void);    //************************************************************// 函数名称: AddRecord,向配置文件追加一条记录// 参 数:    S_TTransferTaskInfo,待追加的记录信息// 返回值:   bool,成功返回true,失败返回false// 权 限:    public //************************************************************virtual bool AddRecord(const S_TTransferTaskInfo sTaskInfo);    // 函数名称: UpdateRecord ,更新配置文件中的一条记录// 参 数:    S_TTransferTaskInfo,待追加的记录信息// 返回值:   bool,成功返回true,失败返回false// 权 限:    public //************************************************************virtual bool UpdateRecord (const S_TTransferTaskInfo sTaskInfo);    // 函数名称: DeleteRecord ,删除配置文件中指定的一条记录// 参 数:    szTaskID,待删除的记录ID// 返回值:   bool,成功返回true,失败返回false// 权 限:    public //************************************************************virtual bool DeleteRecord (const string szTaskID);    // 函数名称: GetPath ,获取设置的本地路径  // 返回值:   本地路径// 权 限:    public //************************************************************virtual string GetPath ();    // 函数名称: GeAlltRecords ,获取配置文件中该用户名下所有的记录信息    // 参 数:    szUserName 当前登陆用户名    // 返回值:   所有该用户名下的未完成任务信息存储容器    // 权 限:    public     //************************************************************    virtual std::vector<S_TTransferTaskInfo> GeAlltRecords(const string szUserName);    // 函数名称: GetRecord ,获取配置文件中指定的某条记录    // 参 数:    szTaskID 记录ID    // 返回值:  记录信息    // 权 限:    public     //************************************************************    virtual S_TTransferTaskInfo GetRecord(const string szTaskID);protected:    private:    string m_sFilePath;};#endif

#include "CFilecontrolManage.h"#include <iostream>#include "CPublicTools.h"using namespace std;const unsigned long ONCE_TIME_TO_READ_NUMBER = 1024;CFilecontrolManage::CFilecontrolManage(void){}CFilecontrolManage::~CFilecontrolManage(void){}//************************************************************// 函数名称: OpenFile,打开文件// 参 数:    string url 路径// 返回值:   EFILE_STATE 返回状态// 权 限:    public //************************************************************EFILE_STATE CFilecontrolManage::OpenFile(std::string url ,ETASK_WORK_TYPE state){   m_sFileUrl = url;   if ( state == UPLOAD_TYPE )   {       CreateReadFile(url);   }   else   {       CreateWriteFile(url);   }   if ( m_mFileHandle == NULL )   {       return OPEN_FILE_FAILE;   }   return OPEN_FILE_SUCCESS;}//************************************************************// 函数名称: CloseFile,关闭文件// 参 数:    void// 返回值:   void// 权 限:    public //************************************************************void CFilecontrolManage::CloseFile(){    if ( m_mFileHandle != NULL )    {        CloseHandle(m_mFileHandle);    }    }//************************************************************// 函数名称: CreateReadFile,获取读文件句柄// 参 数:    void// 返回值:   void// 权 限:    public //************************************************************void CFilecontrolManage::CreateReadFile(std::string url){    if ( m_mFileHandle!=NULL)    {        CloseHandle(m_mFileHandle);    }    LPCWSTR L_url = CPublicTools::getPublicToolsInstance().OnstringToLPCWSTR(url);    m_mFileHandle = ::CreateFile(L_url,        GENERIC_READ ,        FILE_SHARE_READ ,  //文件打开之后就不能再打开        NULL,        OPEN_EXISTING,          FILE_ATTRIBUTE_NORMAL,        NULL        );   #ifdef DEBUG_TYPE    if (m_mFileHandle != INVALID_HANDLE_VALUE)    {        cout<<"获得读文件句柄成功!"<<endl;    }else    {        int ret = GetLastError();        cout<<"获得读文件句柄失败! errID = "<<ret<<endl;    }#endif   }//************************************************************// 函数名称: CreateWriteFile,获取写文件句柄// 参 数:    void// 返回值:   void// 权 限:    public //************************************************************void CFilecontrolManage::CreateWriteFile(std::string url){    LPCWSTR L_url = CPublicTools::getPublicToolsInstance().OnstringToLPCWSTR(url);;    m_mFileHandle = CreateFile(L_url,        GENERIC_WRITE,        0,        NULL,        OPEN_ALWAYS|CREATE_NEW,        FILE_ATTRIBUTE_NORMAL,        NULL        );}//************************************************************// 函数名称: Test,测试专用// 参 数:    void// 返回值:   void// 权 限:    public //************************************************************void CFilecontrolManage::Test(std::string fileName){    m_TestFileName = fileName;}//************************************************************// 函数名称: ReadFile,读取文件// 参 数:    void// 返回值:   void// 权 限:    public //************************************************************DWORD CFilecontrolManage::OnReadFile(LPVOID Readbuff,DWORD Offset,DWORD needToRead){    DWORD BytesRead = 0;    WORD dwPtr = SetFilePointer(m_mFileHandle, Offset, NULL, FILE_BEGIN);    if (dwPtr == INVALID_SET_FILE_POINTER)      {               //获取出错码。              DWORD dwError = GetLastError() ;              //处理出错。                 }    BOOL readRet = ::ReadFile(        m_mFileHandle,                // handle to file        Readbuff,                     // data buffer        needToRead,                   // number of bytes to read        &BytesRead,                   // number of bytes read        NULL                 // overlapped buffer       );#ifdef DEBUG_TYPE    if (readRet)    {        cout << "CFilecontrolManage::OnReadFile 读文件操作失败 "<<BytesRead<<" Offset = "<<Offset<< endl;    }else    {        //获取出错码。        DWORD dwError = GetLastError();             //处理出错。                   TCHAR chErrorBuf[1024];     //   wsprintf(chErrorBuf,"GetLastError()=%d\r\n",dwError);     //   OutputDebugString(chErrorBuf);    }    cout << "CFilecontrolManage::OnReadFile BytesRead = "<<BytesRead<<" Offset = "<<Offset<< endl;#endif    return BytesRead;}//************************************************************// 函数名称: WriteFile,写入文件// 参 数:    void// 返回值:   void// 权 限:    public //************************************************************DWORD CFilecontrolManage::OnWriteFile(LPVOID writeBuff,DWORD Offset,DWORD needToWrite){    string url = "F:/Test/write/"+m_TestFileName+".rar";    LPCWSTR L_url = CPublicTools::getPublicToolsInstance().OnstringToLPCWSTR(url);    HANDLE mFileHandle = CreateFile(L_url,        GENERIC_WRITE,        0,        0,        OPEN_ALWAYS,        FILE_ATTRIBUTE_NORMAL,//   FILE_FLAG_OVERLAPPED,        NULL        );    ///////////////////////////test    WORD dwPtr = SetFilePointer(mFileHandle, Offset, NULL, FILE_BEGIN);    DWORD BytesWritten = 0;    BOOL writeRet = ::WriteFile(        mFileHandle,       // HANDLE hFile,        writeBuff,           //(nNumberOfBytesToWrite) LPCVOID lpBuffer,        needToWrite,         //DWORD nNumberOfBytesToWrite,        &BytesWritten,        //LPDWORD lpNumberOfBytesWritten,        NULL        // LPOVERLAPPED lpOverlapped        );    CloseHandle(mFileHandle);#ifdef DEBUG_TYPE    if (writeRet)    {        cout << "CFilecontrolManage::OnReadFile 写文件操作失败 "<<BytesWritten<<" Offset = "<<Offset<< endl;    }else    {        cout << "CFilecontrolManage::OnWriteFile BytesRead = "<<BytesWritten<<" needToWrite = "<<needToWrite<<" Offset = "<<Offset<< endl;    }    #endif    return BytesWritten;}




这里是一个执行线程,因为上传和下载都是使用不同业务,获取的文件句柄不同。比如上传肯定是获取读的句柄,下载那就是写。使用这里把CreateReadFile、CreateWriteFile分开来了。
0 0