春暖花开
雪化了,花开了,春天来了
posts - 149,comments - 125,trackbacks - 0
 

今天的任务是要保存一个文件。平常看别人怎么写,自己还只是看,没有动手去写过,对各个API相应的参数不是很了解。今天在运用的时候,还真是遇见了一些问题。

我们先来说说问题:
第一个问题:使用WriteFile的时候,我直接将宽字符串写进了文件,文件显示如大家所想,掺杂了很多乱码。但是很有规则。所以我很快就明白了这需要将宽字符串转换成ASCII码。
第二个问题:就是我将文件打开后,又进行了写文件的操作,此时失败。所以对这种情况,还没有想出办法,是由于CreateFile的参数的某些限制么?

由于这两个问题,所以我也好好看了一下SDK文档。
我们先来看一下CreateFileWriteFile的原型和参数介绍:

HANDLE CreateFile(
  LPCTSTR lpFileName,  //
文件名
  DWORD dwDesiredAccess,  //
访问方式
  DWORD dwShareMode,  //
共享模式
  LPSECURITY_ATTRIBUTES lpSecurityAttributes,  //
设为NULL
  DWORD dwCreationDisposition,  ///
创建方式
  DWORD dwFlagsAndAttributes,  //
属性
  HANDLE hTemplateFile
);

BOOL WriteFile(

 HANDLE hFile, // 文件句柄

 LPCVOID lpBuffer, // 包含写向文件的数据

 DWORD nNumberOfBytesToWrite, // 数据包含的字符串的个数

 LPDWORD lpNumberOfBytesWritten,

 LPOVERLAPPED lpOverlapped

);

第一次我写的程序很简单

BOOL WriteOwnFile(TCHAR* pFileName, TCHAR* pBuffer, DWORD dwLen)

{

        HANDLE hFile = CreateFile(pFileName,

                       GENERIC_WRITE,

                                              FILE_SHARE_WRITE,

                                              NULL,

                                              CREATE_ALWAYS,

                                              FILE_ATTRIBUTE_NORMAL,

                                              NULL

                                              );

 

                 if (INVALID_HANDLE_VALUE != hFile)

               {

                                              DWORD dwSize = 0;

                                              WriteFile(hFile, pBuffer, dwLen, &dwSize, NULL );

                                              CloseHandle(hFile);

                                              return TRUE;

               }

               return FALSE;

}

 

这样是完成了,但是写出来的文件是乱码。所以没有进行字符的转换,我们需要将pBuffer进行转换。这就要用到了WideCharToMultiByte.如何用呢?

首先我的方法比较笨,我是这么用的:

char* pchBuffer = new char[dwLen+1];

WideCharToMultiByte(CP_ACP, NULL, pBuffer, -1, pchBuffer, dwLen+1, NULL, FALSE );

WriteFile(hFile, pBuffer, dwLen+1, &dwSize, NULL );

 Delete[] pchBuffer;

 

此时注意,我在WriteFile中用了dwLen+1。结果就是在文件的末尾出现了乱码,正好多一个乱码出来。所以WriteFilenNumberOfBytesToWrite是写的字符串的数目,是不包括’\0’的。

 

这个方法笨,是因为我们的函数可以缩减为两个参数。是因为如下这么写时,dwLen是所要转换的字符串的个数,此时转换的字符串是包括’\0’的。

DWORD dwLen = WideCharToMultiByte(CP_ACP, NULL, pBuffer, -1, NULL, NULL, NULL, FALSE );

 

所以我们再来看一下改写以后的代码

BOOL WriteOwnFile(TCHAR* pFileName, TCHAR* pBuffer)

{

        HANDLE hFile = CreateFile(pFileName,

                       GENERIC_WRITE,

                                              FILE_SHARE_WRITE,

                                              NULL,

                                              CREATE_ALWAYS,

                                              FILE_ATTRIBUTE_NORMAL,

                                              NULL

                                              );

 

                               if (INVALID_HANDLE_VALUE != hFile)

               {

                                              DWORD dwSize = 0;

                                              DWORD dwLen = WideCharToMultiByte(CP_ACP, NULL, pBuffer, -1, NULL, NULL, NULL, FALSE );

                                              char* pchBuffer = new char[dwLen];

                                              WideCharToMultiByte(CP_ACP, NULL, pBuffer, -1, pchBuffer, dwLen, NULL, FALSE );

                                              WriteFile(hFile, pBuffer, dwLen+1, &dwSize, NULL );

                                               delete[] pchBuffer;

                                              CloseHandle(hFile);

                                              return TRUE;

               }

               return FALSE;

}

 

 

这样感觉代码好看多了。

 

对于第二个问题,文件打开的时候文件创建失败,还没有想好办法解决。我在想是不是我的某些认知存在问题,文件打开的时候,是否可以用CreateFile来打开呢?

posted on 2009-02-09 22:14 Sandy 阅读(51927) 评论(13)  编辑 收藏 引用 所属分类: windows学习

FeedBack:
# re: 文件操作:CreateFile和WriteFile的学习
2009-02-10 09:52 | __ay
貌似是可以用的
CreateFile的第五个参数可以来指明打开的文件存在时的处理

还有个OpenFile函数不是吗,也可以用那个来打开个文件

文件打开或者创建失败与否你可以用GetLastError(好像是这个函数)来查看具体原因
  回复  更多评论
  
# re: 文件操作:CreateFile和WriteFile的学习[未登录]
2009-02-10 10:14 | megax
如果你不是非得用ASCII, 其实你不用转换也可以的,如果写宽字符只要在开头的时候写两个字节0xFF,0xFE不就成了Unicode,保证不带乱码的  回复  更多评论
  
# re: 文件操作:CreateFile和WriteFile的学习
2009-02-10 14:15 | Sandy
@__ay
谢谢!
我尝试了CreateFile的第五个参数,改变了一下,好像不可以.用GetLastError,错误值是32,另一个程序正在使用此文件,进程无法访问。似乎这种错误下,不易进行操作。我是要在文件不存在的情况下进行创建,如果存在也是完全覆盖。所以使用了CREATE_ALWAYS。
OpenFile在mobile中好似不支持,在mobile中他利用CreateFile来打开文件的,参数可以是OPEN_EXISTING或OPEN_ALWAYS。  回复  更多评论
  
# re: 文件操作:CreateFile和WriteFile的学习
2009-02-10 14:19 | Sandy
@megax
谢谢!
让我明白了一个小知识。
程序的读和写都是自己控制的,所以我在写文件的时候,没有必要进行字符串。读文件的时候也按照相应的字符读取即可。所以我的代码使用最初的代码就可以了。
不过谢谢了。
  回复  更多评论
  
# re: 文件操作:CreateFile和WriteFile的学习
2009-04-08 14:30 | 战天意
请问Mobile中使用WriteFile需要什么头文件支持吗?我怎么用了没反应啊?  回复  更多评论
  
# re: 文件操作:CreateFile和WriteFile的学习
2009-04-08 17:31 | Sandy
@战天意
只要包含
#include <windows.h>
就可以了.

  回复  更多评论
  
# re: 文件操作:CreateFile和WriteFile的学习
2009-04-08 17:35 | Sandy
DWORD nNumberOfBytesToWrite, // 数据包含的字符串的个数

这个是bytes数, Number of bytes to write to the file

以前没有怎么注意,如果存储TCHAR类型的时候, 就需要注意一下了,需要长度*2的.
  回复  更多评论
  
# re: 文件操作:CreateFile和WriteFile的学习
2009-07-19 15:07 | tzzhwj
怎样在指定的路径上创建一个文件夹啊?谢谢  回复  更多评论
  
# re: 文件操作:CreateFile和WriteFile的学习
2009-07-20 09:40 | Sandy
@tzzhwj

在指定的路径上创建一个文件夹,可以利用CreateDirectory,具体使用可以查一下SDK。
比如我们在根目录下创建一个名为New的文件夹,就可以这样写:
CreateDirectory(_T("\\New"), NULL);
  回复  更多评论
  
# re: 文件操作:CreateFile和WriteFile的学习
2010-04-13 16:28 | passby
我用CreateFile打开文件,第五个参数设为OPEN_EXISTING,结果失败,用GetLastError(),返回值也是32,怎么解决@Sandy
  回复  更多评论
  
# re: 文件操作:CreateFile和WriteFile的学习
2010-04-18 23:18 | Sandy
@passby

呵呵,这个问题我最后也没有解决。只是加了相关的判断。如果你有更好的办法,不妨分享一下。  回复  更多评论
  
# re: 文件操作:CreateFile和WriteFile的学习
2011-04-13 19:44 | faye
我用CreateFile打开文件,第五个参数设为OPEN_EXISTING,结果失败,用GetLastError(),返回值也是32,怎么解决@Sandy
————————————————————————————————

解决这个问题,第六个参数应该包含FILE_FLAG_NO_BUFFERING. 比如FILE_ATTRIBUTE_NORMAL|FILE_FLAG_NO_BUFFERING。  回复  更多评论
  
# re: 文件操作:CreateFile和WriteFile的学习
2012-03-16 20:28 | 小松鼠
@megax
顺序是怎么回事?
声明WORD 时须要:0xfeff
也就是说需要在WriteFile函数之前添加:
WORD Head=0xfeff;
WriteFile(hFile,&Head,sizeof(WORD),&dwWrite,NULL);  回复  更多评论
  

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理