| 
 | 
 
 
发表于 2020-1-26 16:09:01
|
显示全部楼层
 
 
 
文件读取(避免读取半个字符): 
 
/*-----------------------Own_lib函数库系列 mbsfgets.cc------------------------- 
cy_mbsfgets() /mbsfgets.o /libcyfunc.a 
 
描述: 当处理多字节文本文件(如中文)时, 标准fgets()函数只能按字节读入, 这样很容易 
      读入半个字符而使读入的字符串不完整, 为此, 程序中需增加一些额外的处理代码, 
      但这样又让代码看起来不够简洁. 
      本函数试图封装这一过程, 使对东亚文本的读取操作直接一些, 代码也简洁一些. 函 
      数使用了"mbstowcs()/wcstombs()"标准库函数, 所以在您的程序开头应setlocale(). 
      与"fgets()"标准库函数类似, 文件中行尾的换行符被与其它字符同样对待的读入. 
      同样, 字符串的末尾附上了'\0'(空字符)结束符. 
      用户调用函数时: 传递有足够大(MB_CUR_MAX * max_chars +1)内存空间的目的字符 
      串地址(指针) |  最多字符(非字节)数 | 文件流指针 | 和"LC_CTYPE"区域设置字符 
      串(如: "zh_CN.GBK", 默认值为NULL, 表示不改变系统设置. 另当传递了一个无效的 
      区域设置时, 函数不改变当前的该设置, 但该"设置"已为真!). 
      下一个函数为重载函数, 增加了返回实际读取字串字节数的引用变量和返回实际读取 
      字串字符数的引用变量. 
dest_str: 
      保存读入字符串的内存空间的指针/或NULL值. 
max_chars: 
      需要从文件流stream中读入的最多字符个数. 
stream: 
      FILE结构的文件流指针. 
[length]: 
      返回实际读取字符串的字节数. 
[chars]: 
      返回实际读取字符串的字符数. 
locale_ctype = NULL: 
      读入字串所属的LC_CTYPE区域(语系/编码). 一般程序开头已经设定, 故此可不管它. 
返回值: 
      返回指向dest_str内存空间的字符串指针(末尾已加'\0'). 若有错误返回NULL. 
 
注意! 1. 函数从stream读入字符串直到出现换行或到文件尾或已读了max_chars个字符为止. 
      2. 当传递LC_CTYPE区域设置时, 参数dest_str应为NULL, 函数返回指向自由存储区 
         的字符串指针(用完后应delete[]掉, 并赋值为NULL), 若参数dest_str不为NULL, 
         函数移动文件流指针一行/或指定字符数(不足一行时), 返回NULL. 
         当不传递LC_CTYPE设置, 并且设定参数dest_str为NULL时, 其行为与LC_CTYPE为真 
         && dest_str为真(可传递空字符串"")时一样(只有文件流指针移动 && 返回NULL). 
      3. 传入区域字符串后函数将临时改变系统"LC_CTYPE"的设置. 在退出时会恢复其原 
         来的设置. 
 
作者: 任逍 |2002.05.08. 
版权: GNU General (Library) Public License (GPL/LGPL) 
 
* 编辑器: vim-6.0 |操作系统: TurboLinux7.0简体中文版 * 
------------------------------------------------------------------------------*/ 
 
#include <stdio.h>                // usr for fgets() 
#include <stdlib.h>                // usr for MB_CUR_MAX --当前多字节环境下每字最大字节长. 
                                                // usr for mbs* and others. 
#include <locale.h>         // usr for setlocale().--函数提供改变环境"LC_CTYPE"的机会 
 
#include "cyinclude/cyfget.h" 
 
 
char *  cy_mbsfgets(char * dest_str, int max_chars, FILE * stream, 
                    const char * locale_ctype = NULL) 
{ 
        long fpos_before; 
        if ( (fpos_before = ftell(stream)) == -1 )        // 获取读取前的文件流指针位置 
                return NULL; 
 
        int         num = max_chars * MB_CUR_MAX; 
        bool        locale_check = false; 
        char*        locale_original = setlocale(LC_CTYPE, NULL);        // LC_CTYPE原来的值 
        if (locale_ctype) 
        { 
                if (! dest_str) 
                { 
                        setlocale(LC_CTYPE, locale_ctype); 
                        num = max_chars * MB_CUR_MAX; 
                        locale_check = true; 
                } 
                else 
                        dest_str = NULL; 
        } 
 
        size_t         test_length = 0;        // 用于测试输入字符数是否超过需求 
        char*        tmp_chars = new char[num + 1];        // 字串所需最大可能空间, 临时存放用 
        wchar_t*        tmp_wchars = new wchar_t[max_chars + 1]; 
 
        if ( (! tmp_chars) || (! tmp_wchars) ) 
        {        // 其中可能已经有一个申请成功! 
                if (locale_check) 
                        setlocale(LC_CTYPE, locale_original); 
                delete[] tmp_chars; 
                tmp_chars = NULL; 
                delete[] tmp_wchars; 
                tmp_wchars = NULL; 
                return NULL; 
        } 
 
        if (! fgets(tmp_chars, num + 1, stream))        // 接收最大限定数量的输入字符串 
        { 
                if (locale_check) 
                        setlocale(LC_CTYPE, locale_original); 
                delete[] tmp_chars; 
                tmp_chars = NULL; 
                delete[] tmp_wchars; 
                tmp_wchars = NULL; 
                return NULL; 
        } 
 
        test_length = mbstowcs(tmp_wchars, tmp_chars, max_chars + 1); 
        if ( (test_length == (size_t)-1) || (test_length == max_chars + 1) ) 
                tmp_wchars[max_chars] = L'\0';        // 多出来的字符或非法字节被截断或覆盖 
 
        size_t        chars_length;        // 实际读取字串字节长(用于设置文件流指针偏移量) 
        char *        return_chars = NULL; 
        if (locale_check) 
        { 
                chars_length = wcstombs(NULL, tmp_wchars, num + 1); 
                return_chars = new char[chars_length + 1]; 
                if (! return_chars) 
                { 
                        setlocale(LC_CTYPE, locale_original); 
                        delete[] tmp_chars; 
                        tmp_chars = NULL; 
                        delete[] tmp_wchars; 
                        tmp_wchars = NULL; 
                        return NULL; 
                } 
                wcstombs(return_chars, tmp_wchars, chars_length + 1); 
         } 
        else 
                chars_length = wcstombs(dest_str, tmp_wchars, num + 1); 
         
        if (locale_check) 
                setlocale(LC_CTYPE, locale_original); 
 
        delete[] tmp_chars; 
        tmp_chars = NULL; 
        delete[] tmp_wchars; 
        tmp_wchars = NULL; 
         
        if (fseek(stream, fpos_before + chars_length, SEEK_SET)) 
                return NULL;        // 重置文件流指针, 当有错误时, 返回NULL 
 
        if (locale_check) 
                return return_chars; 
        else 
                return dest_str; 
} 
//----------------------------------------------------------------------------- 
 
 
// 上一函数的重载函数.  
 
char *  cy_mbsfgets(char * dest_str, int max_chars, FILE * stream, 
                    int & length, int & chars, const char * locale_ctype = NULL) 
{ 
        long fpos_before; 
        if ( (fpos_before = ftell(stream)) == -1 )        // 获取读取前的文件流指针位置 
                return NULL; 
 
        int         num = max_chars * MB_CUR_MAX; 
        bool        locale_check = false; 
        char*        locale_original = setlocale(LC_CTYPE, NULL);        // LC_CTYPE原来的值 
        if (locale_ctype) 
        { 
                if (! dest_str) 
                { 
                        setlocale(LC_CTYPE, locale_ctype); 
                        num = max_chars * MB_CUR_MAX; 
                        locale_check = true; 
                } 
                else 
                        dest_str = NULL; 
        } 
 
        size_t         test_length = 0;        // 用于测试输入字符数是否超过需求 
        char*        tmp_chars = new char[num + 1];        // 字串所需最大可能空间, 临时存放用 
        wchar_t*        tmp_wchars = new wchar_t[max_chars + 1]; 
 
        if ( (! tmp_chars) || (! tmp_wchars) ) 
        {        // 其中可能已经有一个申请成功! 
                if (locale_check) 
                        setlocale(LC_CTYPE, locale_original); 
                delete[] tmp_chars; 
                tmp_chars = NULL; 
                delete[] tmp_wchars; 
                tmp_wchars = NULL; 
                return NULL; 
        } 
 
        if (! fgets(tmp_chars, num + 1, stream))        // 接收最大限定数量的输入字符串 
        { 
                if (locale_check) 
                        setlocale(LC_CTYPE, locale_original); 
                delete[] tmp_chars; 
                tmp_chars = NULL; 
                delete[] tmp_wchars; 
                tmp_wchars = NULL; 
                return NULL; 
        } 
 
        test_length = mbstowcs(tmp_wchars, tmp_chars, max_chars + 1); 
        if ( (test_length == (size_t)-1) || (test_length == max_chars + 1) ) 
        { 
                tmp_wchars[max_chars] = L'\0';        // 多出来的字符或非法字节被截断或覆盖 
                chars = max_chars;        //!.引用传递返回实际字串字符数 
        } 
        else 
                chars = test_length;        //!.引用传递返回实际字串字符数 
 
        size_t        chars_length;        // 实际读取字串字节长, 用于设置文件流指针偏移量和返回值 
        char *        return_chars = NULL; 
        if (locale_check) 
        { 
                chars_length = wcstombs(NULL, tmp_wchars, num + 1); 
                return_chars = new char[chars_length + 1]; 
                if (! return_chars) 
                { 
                        setlocale(LC_CTYPE, locale_original); 
                        delete[] tmp_chars; 
                        tmp_chars = NULL; 
                        delete[] tmp_wchars; 
                        tmp_wchars = NULL; 
                        return NULL; 
                } 
                wcstombs(return_chars, tmp_wchars, chars_length + 1); 
                length = chars_length;        //!.引用传递返回实际字串字节数 
         } 
        else 
        { 
                chars_length = wcstombs(dest_str, tmp_wchars, num + 1); 
                length = chars_length;        //!.引用传递返回实际字串字节数 
        } 
         
        if (locale_check) 
                setlocale(LC_CTYPE, locale_original); 
 
        delete[] tmp_chars; 
        tmp_chars = NULL; 
        delete[] tmp_wchars; 
        tmp_wchars = NULL; 
         
        if (fseek(stream, fpos_before + chars_length, SEEK_SET)) 
                return NULL;        // 重置文件流指针, 当有错误时, 返回-1 
         
        if (locale_check) 
                return return_chars; 
        else 
                return dest_str; 
} 
 |   
 
 
 
 |