实验七
一、实验目的
(1)熟悉Windows系统文件读\写相关API。
(2)掌握无缓冲方式实现文件读\写相关参数的设置。
二、实验准备
1.文件创建
函数CreateFile( ) 用于创建一个新文件,如果文件已经存在,则得到该文件的句柄。
该函数的参数dwFalgsAndAttributes决定了文件的传输方式,对于普通的文件传输,可将参数设置为FILE_ATTRIBUTE_NORMAL;而若设置为FILE_FLAG_NO_BUFFERING,表示不使用高速缓存进行文件传输;若同时使用标志FILE_FLAG_NO_BUFFERING和FILE_FLAG_OVERLAPPED,可对文件进行异步传输;若设置为FILE_FLAG_SEQUENTIAL_SCAN,表示使用高速缓存进行文件的传输。
原型:
HANDLE CreateFile(
LPCTSTR lpFileName, //指向文件名的指针
DWORD dwDesiredAccess, //读/写访问模式
DWORD dwShareMode, //共享模式
LPSECURITY_ATTRIBUTES lpSecurityAttributes, //指向安全属性的指针
DWORD dwCreationDisposition, //文件存在标志
DWORD dwFlagsAndAttributes, //文件属性
DWORD hTemplateFile //指向访问模板文件的句柄
) ;
dwDesiredAccess:指出访问文件的类型:
值 | 描述 |
---|---|
0 | 查询访问 |
GENERIC_READ | 读访问,从文件中读出数据,且移动文件指针。当需要对文件进行读写时,该属性可以与GENERIC_WRITE组合使用 |
GENERIC_WRITE | 写访问,将数据写入文件,且移动文件指针。当需要对文件进行读/写时,该属性可以与GENERIC_READ组合使用 |
dwShareMode:指出文件共享模式:
值 | 描述 |
---|---|
FILE_SHARE_DELETE | 仅当删除访问时,对文件的打开操作才能成功< |
FILE_SHARE_READ | 仅当读访问时,对文件的打开操作才能成功 |
FILE_SHARE_WRITE | 仅当写访问时,对文件的打开操作才能成功 |
dwCreationDisposition:文件存在标志:
值 | 描述 |
---|---|
CREAT_NEW | 创建新文件。若文件已存在,则该函数调用失败 |
CREAT_ALWAYS | 创建新文件。若文件已存在,则该函数覆盖原文件的内容且清空现有属性 |
OPEN_EXISTING | 打开已存在文件,若文件不存在,则该函数打开失败 |
OPEN_ALWAYS | 若文件存在,则打开该文件,若文件不存在,则以CREAT_NEW方式创建文件 |
TRUNCATE_EXISTING | 打开文件,并将文件的大小截取为0 |
dwFlagsAndAttributes:指出文件属性和标志:
属性 | 描述 |
---|---|
FILE_ATTRIBUTE_ARCHIVE | 文件可以被存档 |
FILE_ATTRIBUTE_HIDDEN | 文件可以被隐藏 |
FILE_ATTRIBUTE_NORMAL | 文件没有其他属性,该属性仅当单独时使用才有效 |
FILE_ATTRIBUTE_OFFLINE | 文件中的数据被脱机存储,文件中的数据不能立即有效 |
FILE_ATTRIBUTE_READONLY | 文件只能读 |
FILE_ATTRIBUTE_SYSTEM | 文件被系统使用 |
FILE_ATTRIBUTE_TEMPORARY | 文件被临时使用 |
返回值:
文件创建成功,该函数返回文件句柄,否则返回INVALID_HANDLE_VALUE,可调用函数GetLastError( )查询失败的原因。
2.读文件
函数Readfile( ) 从文件指针指示的位置开始读取文件中的数据。
原型:
BOOL ReadFILE(
HANDLE hFile, //要读的文件的句柄
LPVOID lpBuffer, //指向文件缓冲区的指针
DWORD nNumberOfBytesToRead, //从文件中要读取的字节数
LPDWORD lpNumberOfBytesRead, //指向从文件中要读取的字节数的指针
LPOVERLAPPED lpOverlapped //指向OVERLAPPED结构的指针
) ;
返回值:
如果函数调用成功,则返回值为非0值。
如果返回非0值,且读出的字节数为0,则说明执行读操作时文件的指针出界,此时调用GetLastError( )函数,可得到返回值ERROR_HANDLE_EOF。但若文件用FILE_FLAG_OVERLAPPED属性打开且参数lpOverlapped不为NULL,则ReadFile( )函数返回为FALSE。
如果函数调用失败,则返回值为0。若要得到更多的错误信息,可调用函数GetLastError( )。
3.写文件
函数WriteFile ( ) 将数据写入文件。函数在文件指针所指的位置完成写操作,写操作完成后,文件指针按实际写入的字节数来调整。
原型:
BOOL WriteFile(
HANDLE hFile, // 要读的文件的句柄
LPVOID lpBuffer, // 指向文件缓冲区的指针
DWORD nNumberOfBytesToWrite, // 从文件中要读取的字节数
LPDWORD lpNumberOfBytesWritten, // 指向从文件中要读取的字节数的指针
LPOVERLAPPED lpOverlapped // 指向 OVERLAPPED结构的指针
) ;
4.关闭文件句柄
函数CloseHandle() 关闭与文件相关的句柄,其作用与释放动态申请的内存空间类似,这样可以释放系统资源,使进程安全运行。
原型:
BOOL CloseHandle(
HANDLE hObject //已打开对象的句柄
);
返回值:
如果函数调用成功,则返回值为非0值。如果函数调用失败,则返回值为0。若要得到更多的错误信息,可调用函数GetLastError()。
三、实验内容
(一)实验内容
建立一个函数,使用该函数将源文件source.txt中的内容读出,再写到目标文件nobuffer.txt中去。
(二)实验代码
// File_NoBuffer.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "File_NoBuffer.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
DWORD BufferSize=1024;
char buf[1024];
/
// The one and only application object
CWinApp theApp;
using namespace std;
void FileReadWrite_NoBuffer(char*source,char*destination);
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
printf("Call FileReadWrite_NoBuffer!\n");
FileReadWrite_NoBuffer("source.txt","nobuffer.txt");
return nRetCode;
}
void FileReadWrite_NoBuffer(char*source,char*destination)
{
HANDLE handle_src,handle_dst;
DWORD NumberOfByteWrite,NumberOfByteRead;
BOOL cycle;
char*buffer;
buffer=buf;
//创建文件
handle_src=CreateFile(source,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_FLAG_NO_BUFFERING,
NULL);
handle_dst=CreateFile(destination,
GENERIC_WRITE,
NULL,
NULL,
CREATE_ALWAYS,
NULL,
NULL);
if(handle_src==INVALID_HANDLE_VALUE ||
handle_dst==INVALID_HANDLE_VALUE)
{
printf("File Create Fail!\n");
exit(1);
}
cycle=TRUE;
while(cycle)
{
NumberOfByteRead=BufferSize;
//读文件
if(!ReadFile(handle_src,buffer,NumberOfByteRead,&NumberOfByteRead,NULL))
{
printf("Read File Error!%d\n",GetLastError());
exit(1);
}
if(NumberOfByteRead<BufferSize)
cycle=FALSE;
//写文件
if(!WriteFile(handle_dst,buffer,NumberOfByteRead,&NumberOfByteWrite,NULL))
{
printf("Write File Error!%d\n",GetLastError());
exit(1);
}
}
CloseHandle(handle_src);
CloseHandle(handle_dst);
}
四、实验结果与总结
运行结果:
运行程序后,我们可以看到在File_NoBuffer文件夹下新建了两个txt文件:source.txt以及nobuffer.txt。一开始两个文件都是空白的,我们试着向source中输入数据并保存。然后运行程序,出现运行成功的提示,然后再次打开nobuffer.txt,这时我们可以看到source.txt中的数据已经复制到了nobuffer.txt中。
总结:
由于一开始我将工程新建在了C盘的C:\Program Files\Microsoft Visual Studio\MyProjects目录下,进行验证时,保存.txt文件时出现了无权限更改的问题,所以我选择更改文件到了其他路径下。