[转] 使用 VC6 进行 UTF-8 格式的文件读写
easyx吧
全部回复
仅看楼主
level 12
yangw80 楼主
这类技术是很成熟的,用 vc 实现这个功能的代码也有很多。我随便搜了一个贴过来。
文章是转的,地址就不贴了,免得帖子被吞。
2013年11月22日 07点11分 1
level 12
yangw80 楼主
UTF-8格式文件的前三字节为0xef,0xbb,0xbf;读取的时候要跳过这三字节解码;写入的时候要先写这三字节到文件头。
包含两个文件。文件一:头文件
/* utf8wr.h */
#ifndef UTF8WR_H
#define UTF8WR_H
#include <stdio.h>
#include <malloc.h>
#include <tchar.h>
#include <windows.h>
size_t utf8_encode(const TCHAR *lpszBuffer,TCHAR *lpszContext);
size_t utf8_decode(const TCHAR *lpszBuffer,TCHAR *lpszContext);
size_t utf8_write(const char *lpszFile,const TCHAR *lpszBuffer);
size_t utf8_read(const char *lpszFile,TCHAR *lpszBuffer);
#endif
2013年11月22日 07点11分 2
level 12
yangw80 楼主
文件2,代码文件:
/* utf8wr.c */
#include "utf8wr.h"
size_t utf8_encode(const TCHAR *lpszBuffer,TCHAR *lpszContext)
{
size_t size=0;
wchar_t *pUnicode=NULL;
if(lpszBuffer==NULL){
return(size);
}
size=MultiByteToWideChar(936,0,lpszBuffer,-1,NULL,0);
if(size>0){
pUnicode=(wchar_t *)malloc(size*sizeof(wchar_t));
if(pUnicode){
MultiByteToWideChar(936,0,lpszBuffer,-1,(LPWSTR)pUnicode,size);
size=WideCharToMultiByte(CP_UTF8,0,(LPWSTR)pUnicode,-1,NULL,0,NULL,NULL);
if(size>0){
if(lpszContext){
size=WideCharToMultiByte(CP_UTF8,0,(LPWSTR)pUnicode,-1,lpszContext,size,NULL,NULL);
}
}
free(pUnicode);
}
}
return(size);
}
size_t utf8_decode(const TCHAR *lpszBuffer,TCHAR *lpszContext)
{
wchar_t *pUnicode=NULL;
size_t size=0;
if(lpszBuffer==NULL){
return(size);
}
size=MultiByteToWideChar(CP_UTF8,0,lpszBuffer,-1,NULL,0);
if(size>0){
pUnicode=(wchar_t *)malloc((size+1)*sizeof(wchar_t));
if(pUnicode){
MultiByteToWideChar(CP_UTF8,0,lpszBuffer,-1,(LPWSTR)pUnicode,size);
size=WideCharToMultiByte(936,0,(LPWSTR)pUnicode,-1,NULL,0,NULL,NULL);
if(lpszContext){
size=WideCharToMultiByte(936,0,(LPWSTR)pUnicode,-1,lpszContext,size,NULL,NULL);
}
free(pUnicode);
}
}
return(size);
}
size_t utf8_write(const char *lpszFile,const TCHAR *lpszBuffer)
{
size_t size1=0;
TCHAR utf8header[3];
TCHAR *psz=NULL;
FILE *fp=NULL;
utf8header[0]=(TCHAR)0xef;
utf8header[1]=(TCHAR)0xbb;
utf8header[2]=(TCHAR)0xbf;
fp=fopen(lpszFile,"wb");
if(fp){
fwrite(utf8header,sizeof(TCHAR),3,fp);
size1=utf8_encode(lpszBuffer,NULL);
if(size1>0){
psz=(TCHAR *)malloc(size1);
if(psz){
size1=utf8_encode(lpszBuffer,psz);
size1=fwrite(psz,sizeof(TCHAR),size1,fp);
free(psz);
psz=NULL;
}
}
fclose(fp);
}
return(size1);
}
size_t utf8_read(const char *lpszFile,TCHAR *lpszBuffer)
{
size_t size=0;
FILE *fp=NULL;
TCHAR *psz=NULL;
fp=fopen(lpszFile,"rb");
if(fp){
fseek(fp,0L,SEEK_END);
size=ftell(fp);
rewind(fp);
if(size>0){
psz=(TCHAR *)malloc(size);
if(psz){
size=fread(psz,sizeof(TCHAR),size,fp);
if(size>3){
if((psz[0]==0xffffffef)&&(psz[1]==0xffffffbb)&&(psz[2]==0xffffffbf)){
size=utf8_decode(psz
+3
,NULL);
if(lpszBuffer){
size=utf8_decode(psz+3,lpszBuffer);
}
}
}
free(psz);
}
}
fclose(fp);
}
return(size);
}
int main()
{
const TCHAR *pszBuffer=_T("中国人民万岁^_^");
TCHAR *psz=NULL;
TCHAR *pszFile="utf8.txt";
size_t size=0;
size=utf8_write(pszFile,pszBuffer);
printf("write %d bytes\n",size);
size=utf8_read(pszFile,NULL);
if(size>0){
psz=(TCHAR *)malloc(size);
if(psz){
size=utf8_read(pszFile,psz);
printf("read %d bytes:\n%s\n",size,psz);
free(psz);
}
}
return(0);
}
运行结果:
write 22 bytes
read 16 bytes:
中国人民万岁^_^
2013年11月22日 07点11分 3
level 11
up up 无意中百度搜索到这,码下:xxx到此一游
2014年02月26日 14点02分 4
level 11
顺便请教一下:
突然发现这个代码读取的文件有时候会发出刺耳声
同一个文件 vc2008 不会,而 vc6.0 就会
不同的文件vc6.0 有的又没声音,苦恼
求解惑,不胜感激!
(........)[无效] http://pan.baidu.com/s/1eQ9TTeU
2014年02月26日 15点02分 5
声音???你能不能单步调试一下,看看执行到哪一行的时候会发出声音呢?
2014年03月01日 14点03分
我这里执行了你的代码,并没有任何声音啊。
2014年03月01日 14点03分
回复 yangw80 :我得先百度一下怎么调试。。。[我错了]
2014年03月02日 04点03分
level 11
我注释掉 cout << psz << endl; 就没声音了,
发现读取后 psz 末尾有几个乱码字,难道是这个作怪
2014年03月02日 04点03分 6
估计是 malloc 空间的时候要多了,又没有设置空结尾。纯猜测。
2014年03月02日 12点03分
level 11
#include <windows.h>
#include <stdio.h>
#include <fstream>
#include <iostream>
using namespace std;
#pragma warning ( disable : 4996 )
//
void main()
{
FILE* fp = fopen( "f:\\aa.txt", "rb" );
fseek( fp, 0, SEEK_END );
size_t size = ftell( fp ); // 文件字节大小,不包含文件结尾,但是包含了文件头的 3 字节
fseek( fp, 3, SEEK_SET ); // 跳过文件头标识 0xEF、0xBB、0xBF
char* p = new char[ size - 3 + 1 ]; // 去掉文件头 3 字节标识符,增加一个空结尾
p[size - 3] = '\0'; // 去掉这个结果就不对了,后面的 n 超出大小
fread( p, sizeof(char), size - 3, fp );
int n = MultiByteToWideChar( CP_UTF8, 0, p, -1, NULL, 0 ); // 返回的是宽字符数,而不是字节数!!!,空结尾也算一个字符
cout << strlen(p) << " - " << n << " - " << size << endl; // 10、7、13 strlen() 不计算空结尾,此时貌似一个中文 3 字节,一个英文 1 字节
wchar_t* wp = new wchar_t[ n * sizeof(wchar_t) ]; // 给 7 个字符 "啊acxa啊\0" 申请空间
MultiByteToWideChar( CP_UTF8, 0, p, -1, wp, n );
int mm = WideCharToMultiByte( 936, 0, wp, -1, NULL, 0, NULL, NULL ); // 此时返回的是字节数,而不是字符数了!!!
cout << mm << endl; // mm = 9,ASCII:一个中文 2 字节,一个英文 1 字节,空结尾 1 字节
char* asi = new char[ mm * sizeof(char) ];
WideCharToMultiByte( 936, 0, wp, -1, asi, mm, NULL, NULL );
cout << asi << endl;
delete [] p;
delete [] wp;
delete [] asi;
fclose( fp );
_getch();
}
/*** 文件 aa.txt 内容:没有回车,unicode 下,一个回车都占 4 字节!!11!!!!
啊acxa啊
**/
2014年03月02日 12点03分 7
这是从顶楼提取出来的 读取 utf8 的代码。PS:从上面过滤出这个代码还真辛苦。
2014年03月02日 12点03分
回复 fammy043 :如果把 p[size - 3] = '\0'; 注释掉,我这电脑又会发出一个警报声。。。而且最后面的输出结果会多出几个乱码
2014年03月02日 12点03分
level 11
感觉 utf8_read() 里面的 psz = (char *)malloc( size );
要多留一个位置出来给 NULL 结尾:
psz = (char*)malloc( size + 1 );
2014年03月02日 13点03分 9
是了,还要加上 psz[size] = '\0'; 这样之后我这就正常了,没有声音,最后也没有乱码
2014年03月02日 13点03分
level 12
yangw80 楼主
哦,是的,输出 ascii 码的 7,就能让喇叭发出声音。如果超出结尾的时候,遇到了 7,就会出声音。
2014年03月15日 11点03分 10
1