/***************************************************************
* 函数名称:函数getFileChar负责按每个字符读写文件,文件级操作
函数mac2dos负责判断,把CR或LF格式转换成CR/LF文件格式
* 功能描述:函数mac2dos负责把UINX文件格式转换成DOS文件格式
原理:
Dos和windows采用回车+换行CR/LF表示下一行,
而UNIX/Linux采用换行符LF表示下一行,
苹果机(MAC OS系统)则采用回车符CR表示下一行.
本程序把CR 或 LF 的文本转换成CR/LF的文本
* 局限性: 实现有缺漏,无法达到满意效果,如OD 00 OA 00情况没有考虑
可对unix/linux/mac/dos混合的文件,进行转换,但会产生多个空行。
因为之前是CR或LF,经转换后为0D000A00,这时接入的00是多余的,必须删除,否则会乱码。
为FF时候就省去该换页符,即0C 00 不进入out流。
深层次原因:中文总是从文件偶数个字符开始的,每两个字符表示一个汉字如,文:CE C4
与英文字符在一块的CR/LF特殊状态是0D0A,与中文字符在一起的则是0D000A00.
所以如果转换0D或0A后遇到的下一个字符是非00字符,那就表示是英文字母。
如果转换0D或0A后遇到的下一个字符是00,那就表示是中文,可以删去该00。
* 输入参数:
char *path = "E://RES//1.txt"类型,待转换的文件绝对路径
返回参数:
int 值0 ,代表正常结束;值1 ,代表中途出现过问题;
* 外部依赖:
* 写作时间:2011.05.26 1.0版
* 修改时间:2011.05.29 1.1版
* 用法举例:
int main(string DestDir,string strRet,string model = "r")
{
char* file1 = "E://RES//1.txt";
char* Dir = file1;
if ( getFileChar(Dir) == 0 )
{
printf("mac2dos is success./n");
}
else
{
printf("mac2dos is fail./n");
}
system("pause");
return 0;
}
*
****************************************************************/
#include <iostream>
#include <io.h>
#include <sys/utime.h>
using namespace std;
const static int LF=0x0A;// 换行符,可以以int来写入文件流,就相当于以换行符输入文件流
const static int CR=0x0D;// 回车符,可以以int来写入文件流,就相当于以回车符输入文件流
const static int FF=0x0C;// 换页符, 走纸控制,可以以int来写入文件流,就相当于以换页符输入文件流
const static int ZERO=0x00;//null空字符,可以以int来写入文件流,就相当于以回车符输入文件流,
//因为putc只能输出一个字符,所以0D 00 或0A 00 转到0D 00 0A 00 就需要00输出一次了
//结构类型定义,结构变量;#include <sys/stat.h>的struct stat结构是stat函数可以返回的结构,
//里面包括文件的全部属性。返回值:若成功则返回0,失败则返回-1
struct stat s_buf;
//函数getFileChar负责按每个字符读写文件,文件级操作
int getFileChar (char *path);
//函数mac2dos负责判断,把CR或LF格式转换成CR/LF文件格式
int mac2dos(char ch,char buffer[],char &writebuffer,int &index,bool &isClear);
int getFileChar (char *path )
{
FILE *in, *out; //指向文件的指针,即FILE*文件流(管道应用);in用来读入,out用来输出。
bool status = true;//表示已经出错状态,初始化为false,即暂时没出错。
char ch = 0x00,//当前处理字符
prev_ch= 0x00;//prev_ch是用来指示重复字符
//缓冲读取的字符,以便判读
char buffer[4] = {'0','0','0','0'};
//存在两个个连续CR时,需要用writebuffer缓存第二个CR
char writebuffer = '0';
int index = 0;
//是否马上写入文件
bool isClear = true;
//缓冲临时文件路径,16字符的数组temppath,实际上除了结束符占一个字符外,只能存取15字符.
char temppath [16];
struct _utimbuf ut_buf; //在Windows NT和Windows95下,你可以改变utimbuf结构中的访问时间和修改时间。用来设定文件属性
//建立一个临时文件。
strcpy (temppath, "./clntmp");//把src所指由NULL结束的字符串复制到dest所指的数组中。
strcat (temppath, "XXXXXX");//功能:把src所指字符串添加到dest结尾处(覆盖dest结尾处的'/0')并添加'/0'。
mktemp (temppath);//mktemp()用来产生唯一的临时文件名。参数template所指的文件名称字符串中最后六个字符必须是XXXXXX。产生后的文件名会借字符串指针返回。
// 返回值: 文件顺利打开后,指向该流的文件指针就会被返回。如果文件打开失败则返回NULL,并把错误代码存在errno中。
//---打开文件----------------------------------------------------------------------
if ((in=fopen (path, "rb")) == NULL)
{
//如果in等于NULL,即(FILE *) 0,表示打开文件失败,
status = false;
}
else if ((out=fopen (temppath, "wb")) == (FILE *) NULL)
{
//如果out等于NULL,即(FILE *) 0,表示打开文件失败,
//fclose(in)善后处理,取消本次不成功流程
fclose (in);
status = false;
}
else
{
//---开始转化,对每个字符进行遍历,处理后将写入临时文件----------------------------------------------------
while ((ch = getc (in)) != EOF)
{
// 当ch也就是getc(in)的返回值不等于EOF文件尾结束符时,进行该循环;
// getc功 能: 从流中取一个字符进行处理
mac2dos(ch, buffer,writebuffer,index,isClear);
if ( isClear == true)
{
for ( int i = 0; i < index; ++i)
{
putc(buffer[i], out);
}
//本次写入结束
index = 0;
}
} // while 结束,文件转化完毕
printf("mac2dos is success./n");
} // else 结束
//fclose若关闭文件动作成功则返回0,有错误发生时则返回EOF。流成功关闭,fclose 返回 0,否则返回EOF(-1)。
if (fclose (in) == EOF)
{
status = false; //表示已经出错状态
}
if (fclose (out) == EOF)
{
status = false; //表示已经出错状态
}
//---后期处理----------------------------------------------------------------------
ut_buf.actime = s_buf.st_atime; //最后一次访问的时间
ut_buf.modtime = s_buf.st_mtime;//文件内容最后一次被更改的时间
if (_utime (temppath, &ut_buf) == -1)//修改文件属性出错
//#include <time.h> int utime(const char pathname, const struct utimbuf *times);返回值:成功返回0,失败返回-1
status = false; //表示已经出错状态
//原子性:1、删除原文件(成功);2、重名名临时文件为原文件(成功);3;删除临时文件(成功)---->成功
// 1、删除原文件(成功);2、重名名临时文件为原文件(失败)---->出错提示,失败
// 1、删除原文件(失败);2、删除临时文件---->失败
//1、删除原文件,用unlink()函数来清除临时文件path,即删除原文件,成功返回0,失败返回-1。
if (unlink (path) == 0 )
{
//删除原文件(成功)
//2、重名名临时文件为原文件
if ( rename (temppath,path) == 0 )
{
//3;删除临时文件
unlink (temppath);//转换成功结束
}
else
{
//重命名出错提示
fprintf (stderr, "Unix2Dos: Problems renaming '%s' to '%s'./n", temppath, path);
fprintf (stderr, " However, file '%s' remains./n", temppath);
status = false;
}
}
else
{
//删除原文件(失败)
//删除临时文件
unlink (temppath);//用unlink()函数来清除临时文件temppath,即删除原文件,成功返回0,失败返回-1。
status = false; //出错状态,函数返回true。
}
return status ? 0 : 1;
}
int mac2dos(char ch,char buffer[],char &writebuffer,int &index,bool &isClear)
{
//清空标志,然后处理时按需要自己决定是否需要即时写入文件
isClear = true;
//上次碰到连续两个CR的情况,处理writebuffer
if ( writebuffer == CR )
{
buffer[0] = CR;
index = 1;
//writebuffer清空,只有在碰到连续两个CR才进入本语句块
writebuffer = '0';
isClear = false;
}
//程序缓存会在遇到CR临时存储不写入文件,遇到LF和其他字符时转换成CR/LF写入文件。
buffer[index] = ch;
++index;
switch ( ch )
{
case CR:
if ( index == 1 )
{
//当前缓存只存在1个CR
isClear = false;
}
else if ( index == 2 )
{
//当前缓存存在连续两个CR,可以释放一个CR,
//第一个CR需要转换成CR/LF的DOS格式
buffer[0] = CR;
buffer[1] = LF;
index = 2;
//缓存第二个CR,下次处理
writebuffer = CR;
isClear = true;
}
break;
case LF:
if ( index == 1)
{
//buffer只缓存一个字符LF,需要转换成CR/LF的DOS格式
buffer[0] = CR;
buffer[1] = ch;
index = 2;
isClear = true;
}
if ( index == 2 && buffer[0] == CR && buffer[1] == LF )
{
//buffer中已经缓存CR,形成CR/LF,不需转换
isClear = true;
}
break;
case FF:
//其他字符,会直接导致缓存的字符转换成CR/LF的DOS格式,清空效果
//贯穿!
case ZERO:
//暂不处理
//其他字符,会直接导致缓存的字符转换成CR/LF的DOS格式,清空效果
//贯穿!
default:
//其他字符(包括FF、ZERO),会直接导致缓存的字符转换成CR/LF的DOS格式,清空效果
if ( index == 1 )
{
//buffer未缓存其他字符
}
else if ( (index == 2) && (buffer[0] == CR) )
{
//buffer缓存字符CR,需要转换成CR/LF的DOS格式
buffer[0] = CR;
buffer[1] = LF;
buffer[2] = ch;
index = 3;
}
//缓冲区字符直接写入文件
isClear = true;
break;
}
return 0;
}