您现在的位置: 365建站网 > 365学习 > C/C++ 文件操作之CreateFile函数、ReadFile函数和WriteFile函数的用法

C/C++ 文件操作之CreateFile函数、ReadFile函数和WriteFile函数的用法

文章来源:365jz.com     点击数:805    更新时间:2018-10-27 10:59   参与评论

1. CreateFile函数

  这个函数的功能是创建或者打开一个文件或者I/O设备,通常使用的I/O形式有文件、文件流、目录、物理磁盘、卷、终端流等。如执行成功,则返回文件句柄。 INVALID_HANDLE_VALUE 表示出错,会设置 GetLastError 。 

  函数的声明定义:

  HANDLE WINAPI CreateFile(
  _In_      LPCTSTR lpFileName,              
  _In_      DWORD dwDesiredAccess,
  _In_      DWORD dwShareMode,
  _In_opt_  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  _In_      DWORD dwCreationDisposition,
  _In_      DWORD dwFlagsAndAttributes,
  _In_opt_  HANDLE hTemplateFile
);

参数列表:

参数类型描述
lpFileNameString ,要打开的文件的名字
dwDesiredAccessLong ,如果为 GENERIC_READ 表示允许对设备进行读访问;如果为 GENERIC_WRITE 表示允许对设备进行写访问(可组合使用);如果为零,表示只允许获取与一个设备有关的信息
dwShareModeLong ,零表示不共享; FILE_SHARE_READ 和 / 或 FILE_SHARE_WRITE 表示允许对文件进行共享访问
lpSecurityAttributesSECURITY_ATTRIBUTES ,指向一个 SECURITY_ATTRIBUTES 结构的指针,定义了文件的安全特性(如果操作系统支持的话)
dwCreationDispositionLong ,下述常数之一:CREATE_NEW 创建文件; 如文件存在则会出错CREATE_ALWAYS 创建文件,会改写前一个文件;OPEN_EXISTING 文件必须已经存在。由设备提出要求;OPEN_ALWAYS 如文件不存在则创建它;    TRUNCATE_EXISTING 将现有文件缩短为零长度
dwFlagsAndAttributesLong ,一个或多个下述常数: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 关闭了上一次打开的句柄后,将文件删除。特别适合临时文件;
hTemplateFileLong ,如果不为零,则指定一个文件句柄。新文件将从这个文件中复制扩展属性

参数:

lpFileName [in]

    要创建或打开的文件或设备的名称。 可以在这个名字中使用正斜杠(/)或反斜杠(\)【注意/是转义符号】。在该函数的ANSI版本中,该名称仅限于MAX_PATH字符。要将此限制扩展为32,767个宽字符,请调用该函数的Unicode版本并将“\\?\”添加到路径中。更多内容请查看:Naming Files, Paths, and Namespaces.
    有关特殊设备名称的信息,请参阅:Defining an MS-DOS Device Name.
    要创建文件流,请指定文件的名称,冒号,然后指定流的名称。 有关更多信息,请参阅File Streams.
    提示:从Windows 10版本1607开始,针对此函数的unicode版本(CreateFileW),您可以选择删除MAX_PATH限制而不预先添加“\\?\”有关详细信息,请参阅命名文件,路径和命名空间的“Naming Files, Paths, and Namespaces ”部分。
dwDesiredAccess [in]
    所请求的文件或设备访问权限,这可以被概括为读,写,两者或非)。最常用的值是GENERIC_READGENERIC_WRITE或两者(GENERIC_READ | GENERIC_WRITE)。更多内容查看;Generic Access Rights, File Security and Access Rights, File Access Rights Constants, and ACCESS_MASK.
    如果此参数为零,则应用程序可以查询某些元数据(如文件,目录或设备属性),而不访问该文件或设备,即使GENERIC_READ访问已被拒绝。
    您无法请求与已打开句柄的打开请求中的dwShareMode参数指定的共享模式冲突的访问模式。
    有关更多信息,请参阅本主题的“备注”部分和Creating and Opening Files.
dwShareMode [in]
    文件或设备的请求共享模式,可以读取,写入,删除,全部或全部删除。对属性或扩展属性的访问请求不受此标志的影响。
    如果此参数为零且CreateFile成功,则文件或设备无法共享,并且无法再次打开,直到文件或设备的句柄关闭。
    你无法请求与在具有打开句柄的现有请求中指定的访问模式冲突的共享模式。 CreateFile将失败,GetLastError函数将返回ERROR_SHARING_VIOLATION。
    要启用进程在另一进程打开文件或设备时共享文件或设备,请使用以下一个或多个值的兼容组合。有关此参数与dwDesiredAccess参数的有效组合的更多信息,请查看Creating and Opening Files.
提示:每个打开的句柄的共享选项在该句柄关闭之前保持有效,而与流程上下文无关。

ValueMeaning
0x00000000 防止其他进程在请求删除,读取或写入访问时打开文件或设备。

FILE_SHARE_DELETE                               

0x00000004

启用文件或设备共享删除访问,否则,如果其他进程请求删除访问,则无法打开该文件或设备。如果未指定此标志,但文件或设备已被打开以进行删除访问,则该功能失败。

注意:除访问权限允许删除和重命名操作

FILE_SHARE_READ

0x00000001

启用文件或设备共享读访问,否则,如果其他进程请求读取访问权限,则无法打开文件或设备。如果未指定此标志,但文件或设备已被打开以进行读取访问,则该功能失败。

FILE_SHARE_WRITE

0x00000002

启用文件或设备共享写访问,否则,如果其他进程请求写访问权限,则无法打开该文件或设备。如果未指定此标志,但文件或设备已打开以进行写入访问或具有写入访问的文件映射,则该功能将失败。

lpSecurityAttributes [in, optional]
    指向SECURITY_ATTRIBUTES结构的指针,该结构包含两个独立但相关的数据成员:一个可选的安全描述符以及一个布尔值,该值确定返回的句柄是否可以被子进程继承。
    该参数可以是NULL。
    如果此参数为NULL,则由CreateFile返回的句柄不能由应用程序可能创建的任何子进程继承,并且与返回句柄关联的文件或设备将获得默认安全描述符。
    该结构的lpSecurityDescriptor成员为文件或设备指定SECURITY_DESCRIPTOR。如果此成员为NULL,则与返回句柄关联的文件或设备将被分配一个默认安全描述符。
    CreateFile在打开现有文件或设备时会忽略lpSecurityDescriptor成员,但会继续使用bInheritHandle成员。
    该结构的bInheritHandle成员指定是否可以继承返回的句柄。
dwCreationDisposition [in]
    采取存在或不存在的文件或设备的操作。
    对于文件以外的设备,此参数通常设置为OPEN_EXISTING。

    该参数必须是以下值之一,不能组合:

ValueMeaning

CREATE_ALWAYS

2

始终创建一个新文件。

如果指定的文件存在并且是可写的,则该函数覆盖文件,函数成功,并且最后的错误代码被设置为ERROR_ALREADY_EXISTS(183)。

如果指定的文件不存在并且是有效的路径,则会创建一个新文件,该函数成功,并且最后一个错误代码被设置为零。

CREATE_NEW

1

只有在不存在的情况下才创建一个新文件。
如果指定的文件存在,则该函数失败,并且最后的错误代码被设置为ERROR_FILE_EXISTS(80)。
如果指定的文件不存在并且是可写位置的有效路径,则会创建一个新文件。
OPEN_ALWAYS
4
总是打开一个文件。
如果指定的文件存在,则函数成功并且最后的错误代码被设置为ERROR_ALREADY_EXISTS(183)。
如果指定的文件不存在并且是可写位置的有效路径,则该函数将创建一个文件,并将最后一个错误代码设置为零。
OPEN_EXISTING
3
只有存在文件或设备时才打开。
如果指定的文件或设备不存在,则该函数将失败,并且最后一个错误代码将设置为ERROR_FILE_NOT_FOUND(2)。
TRUNCATE_EXISTING           
5
打开一个文件并截断它,以便它的大小为零字节,只要它存在。
如果指定的文件不存在,则该函数失败,并且最后的错误代码被设置为ERROR_FILE_NOT_FOUND(2)。
调用进程必须打开GENERIC_WRITE位设置为dwDesiredAccess参数的一部分的文件。

dwFlagsAndAttributes [in]
    文件或设备属性和标志FILE_ATTRIBUTE_NORMAL是文件最常用的默认值。
   此参数可以包含可用文件属性的任意组合(FILE_ATTRIBUTE_ *)。 所有其他文件属性都会覆盖FILE_ATTRIBUTE_NORMAL。
    此参数还可以包含用于控制文件或设备缓存行为,访问模式和其他特殊用途标志的标志组合(FILE_FLAG_ *)。 这些与任何FILE_ATTRIBUTE_ *值结合使用。
    此参数还可以通过指定SECURITY_SQOS_PRESENT标志来包含安全服务质量(SQOS)信息。
    当CreateFile打开现有文件时,它通常将文件标志与现有文件的文件属性组合在一起,并忽略作为dwFlagsAndAttributes的一部分提供的任何文件属性。
    官方文档中还有列出很多文件和设备属性和标志的表格,内容太多不再列出,建议参考原文。
hTemplateFile [in, optional]
    具有GENERIC_READ访问权限的模板文件的有效句柄。模板文件为正在创建的文件提供文件属性和扩展属性。
    该参数可以是NULL。
    打开现有文件时,CreateFile将忽略此参数。

    打开新的加密文件时,该文件从其父目录继承自主访问控制列表。


返回值:
    如果函数成功,则返回值是指定文件,设备,命名管道或邮件插槽的打开句柄。

    如果该函数失败,则返回值为INVALID_HANDLE_VALUE。 要获得扩展的错误信息,请调用GetLastError。

备注:

    CreateFile最初是专门为文件交互而开发的,但后来被扩展和增强,以包括Windows开发人员可用的大多数其他类型的I / O设备和机制。本节试图涵盖开发人员在不同上下文和不同I / O类型中使用CreateFile时可能遇到的各种问题

下面的代码实现了在文件末尾写入数据的过程:



#include <stdio.h>
#include <windows.h>
int main()
{
    HANDLE hFILE=CreateFile("1.txt",GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
    if(hFILE==INVALID_HANDLE_VALUE)
    {
        printf("CreateFile error\n");
        return 0;
    }
    if(SetFilePointer(hFILE,0,NULL,FILE_END)==-1)
    {
        printf("SetFilePointer error\n");
        return 0;
    }
    char buff[256]="hello";
    DWORD dwWrite;
    if(!WriteFile(hFILE,&buff,strlen(buff),&dwWrite,NULL))
    {
        printf("WriteFile error\n");
        return 0;
    }
    printf("write %d.\n",dwWrite);
    printf("done.\n");
    CloseHandle(hFILE);
    return 0;
}


2. ReadFile函数

  从文件指针指向的位置开始将数据读出到一个文件中, 且支持同步和异步操作,如果文件打开方式没有指明FILE_FLAG_OVERLAPPED的话,当程序调用成功时,它将实际读出文件的字节数保存到lpNumberOfBytesRead指明的地址空间中。FILE_FLAG_OVERLAPPED 允许对文件进行重叠操作。 

  函数声明定义:

  BOOL WINAPI ReadFile(
  __in          HANDLE hFile,                   // 文件句柄
  __out         LPVOID lpBuffer,                // 接收数据用的 buffer
  __in          DWORD nNumberOfBytesToRead,     // 要读取的字节数
  __out         LPDWORD lpNumberOfBytesRead,    // 实际读取到的字节数
  __in          LPOVERLAPPED lpOverlapped       // OVERLAPPED 结构,一般设定为 NULL 
);

代码示例:

BOOL Read(char *filePath)
{
    HANDLE pFile;
    DWORD fileSize;
    char *buffer,*tmpBuf;
    DWORD dwBytesRead,dwBytesToRead,tmpLen;
    pFile = CreateFile(filePath,GENERIC_READ,          
        FILE_SHARE_READ,
        NULL,               
        OPEN_EXISTING,        //打开已存在的文件 
        FILE_ATTRIBUTE_NORMAL, 
        NULL);
    if ( pFile == INVALID_HANDLE_VALUE)
    {
        printf("open file error!\n");
        CloseHandle(pFile);
        return FALSE;
    }
    fileSize = GetFileSize(pFile,NULL);          //得到文件的大小
    buffer = (char *) malloc(fileSize);
    ZeroMemory(buffer,fileSize);
    dwBytesToRead = fileSize;
    dwBytesRead = 0;
    tmpBuf = buffer;
    do{                                       //循环读文件,确保读出完整的文件    
        ReadFile(pFile,tmpBuf,dwBytesToRead,&dwBytesRead,NULL);
        if (dwBytesRead == 0)
            break;
        dwBytesToRead -= dwBytesRead;
        tmpBuf += dwBytesRead;
        } while (dwBytesToRead > 0);
        //  TODO 处理读到的数据 buffer
    free(buffer);
    CloseHandle(pFile);
    return TRUE;
}


// CreateFile.cpp : 定义控制台应用程序的入口点。
//此代码将该CPP文件中的类容完整输出在控制台。也可以利用该函数进行拷贝文本文件,实际读取字节要比定义的结构体小一字节,否则会没有结束标志哦
#include "stdafx.h"
#include <windows.h>
#include "iostream"
using namespace std;
int main()
{
HANDLE hFile = CreateFile(TEXT("CreateFile.cpp"), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
CHAR FileContext[256];
DWORD ReadInt = 0;
if (hFile == INVALID_HANDLE_VALUE)
{
cout << "Open file failed! LastError is " << GetLastError() << endl;
}
while (ReadFile(hFile, FileContext,255,&ReadInt,NULL)>0 && ReadInt>0)
{
cout << FileContext << endl;
memset(FileContext,0,sizeof(FileContext));
}
   
system("Pause");
return 0;
}


3. WriteFile函数

  将数据写入一个文件。该函数比fwrite函数要灵活的多。也可将这个函数应用于对通信设备、管道、套接字以及邮槽的处理。返回时,TRUE(非零)表示成功,否则返回零。会设置GetLastError。 

函数声明定义:


BOOL WINAPI WriteFile(
  __in          HANDLE hFile,                   // 文件句柄
  __in          LPCVOID lpBuffer,               // 要写入的数据
  __in          DWORD nNumberOfBytesToWrite,    // 要写入的字节数
  __out         LPDWORD lpNumberOfBytesWritten, // 实际写入的字节数
  __in          LPOVERLAPPED lpOverlapped       // OVERLAPPED 结构,一般设定为 NULL
);

代码示例:


BOOL Write(char *buffer, DWORD contentLen)
{
    HANDLE pFile;
    char *tmpBuf;
    DWORD dwBytesWrite,dwBytesToWrite;
    pFile = CreateFile(filePath,GENERIC_WRITE,          
        0,
        NULL,               
        CREATE_ALWAYS,        //总是创建文件
        FILE_ATTRIBUTE_NORMAL, 
        NULL);
    if ( pFile == INVALID_HANDLE_VALUE)
    {
        printf("create file error!\n");
        CloseHandle(pFile);
        return FALSE;
    }
    dwBytesToWrite = contentLen;
    dwBytesWrite = 0;
    tmpBuf = buffer;
    do{                                       //循环写文件,确保完整的文件被写入  
        WriteFile(pFile,tmpBuf,dwBytesToWrite,&dwBytesWrite,NULL);
        dwBytesToWrite -= dwBytesWrite;
        tmpBuf += dwBytesWrite;
        } while (dwBytesToWrite > 0);
    CloseHandle(pFile);
    return TRUE;
}


如对本文有疑问,请提交到交流论坛,广大热心网友会为你解答!! 点击进入论坛


发表评论 (805人查看0条评论)
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
用户名: 验证码: 点击我更换图片
最新评论
------分隔线----------------------------