热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Linux下/QtUTF8转GB2312

1.背景项目需要用到热敏打印机,控制接口为串口(RS232),运行环境为LinuxQt。在此之前,在MCU平

1.背景

项目需要用到热敏打印机,控制接口为串口(RS232),运行环境为Linux+Qt。在此之前,在MCU平台的实时系统(RT-Thread)上已经实现出正确的打印功能,原则上把代码移植过来,调整下打印位置、字体大小等即可。代码移植后,运行结果是英文、数字打印正常,中文打印则出现乱码。现有的配置情况是,热敏打印机提供的英文、数字字库是ASII格式,中文字库是GB2312格式,平台控制端采用UTF-8编码格式,C++代码编写。因此基本可以确定是编码问题。

2.处理方法1——简单粗暴,将文件格式由UTF-8转为ANSI(windows只有这个格式选项,在简体中文系统下,ANSI代表GB2312)

鉴于之前开发的项目,团队成员之间或者其他电脑查阅源码工程时,都会莫名其妙的乱码,所以从此项目开始,所有源码编码的都采用UTF-8的保存格式(这个可以Qt Creator中设置),打印内容文件也是UTF-8保存。在此之前,记得上一东家同事的文件格式采用ANSI时,无需作编码转换即可正常打印中文。本人也做个尝试,将打印内容的文件改为ANSI格式(windows下用记事本打开->另存为->选择ANSI->保存)。结果很遗憾,打印还是乱码。也许是设置或者某些细节问题,这个我没有深入研究,因为比较感兴趣的是编码转换问题。

结论:该方法本人未能成功实现,后续再深入研究,欢迎大家分享经验。

3.处理方法2——iconv

iconv基于GPL公开源代码,是GNU项目的一部分,在各种Unix-like操作系统下很容易编译和使用,从网络上也能找到大牛介绍或者利用该函数写的编码转换源码【1】。所以,本人首先在Linux下,用C编写程序,调用该函数实现转换,然后再移植到Qt下面用C++方式实现,Linux下经过测试可以正常打印。关键代码如下:

保存为C源文件时,必须以UTF-8的格式。

#include /* 标准输入、输出定义 */
#include /* UNIX 标准函数定义 */
#include /* 文件控制定义 */
#include /* 错误编号定义 */
#include /* POSIX 终端控制定义 */
#include /* 字符串函数定义 */
#include
#define SERIAL_PORT "/dev/ttySAC3" //ARM串口端口
#define BAUDRATE B9600 //9600bps
#define MAX_SIZE 255/** \brief 打开串行端口一* \brief 成功后返回文件描述符,或是失败后返回-1*/
int code_convert(char *from_charset,char *to_charset,char *inbuf,int inlen,char *outbuf,int outlen)
{iconv_t cd;printf("in= %s\n",inbuf);char **pin = &inbuf;char **pout = &outbuf;char *old;old = outbuf;cd = iconv_open(to_charset,from_charset);if(cd==(iconv_t)-1){printf("iconv open failed!\n");perror("iconv_open");return -1;}memset(outbuf,0,outlen);if (iconv(cd,pin,(size_t*)&inlen,pout,(size_t*)&outlen) == -1){printf("iconv failed!\n");perror("iconv");}iconv_close(cd);printf("out= %s\n",&outbuf);return outbuf - old;
}int gb2312_utf8(char *inbuf,int inlen,char *outbuf,int outlen)
{return code_convert("gb2312","utf-8",inbuf,inlen,outbuf,outlen);
}int utf8_gb2312(char *inbuf,int inlen,char *outbuf,int outlen)
{return code_convert("utf-8","gb2312",inbuf,inlen,outbuf,outlen);
}int gb2312_ucs2(char *inbuf,int inlen,char *outbuf,int outlen)
{return code_convert("gb2312","ucs-2",inbuf,inlen,outbuf,outlen);
}int ucs2_gb2312(char *inbuf,int inlen,char *outbuf,int outlen)
{return code_convert("ucs-2","gb2312",inbuf,inlen,outbuf,outlen);
}int open_port()
{int fd; /* 端口文件描述符 */fd = open(SERIAL_PORT, O_RDWR | O_NOCTTY | O_NDELAY);if (fd == -1){perror("open_port: Unable to open /dev/ttyS0 - ");}return (fd);
}void set_port(int fd)
{struct termios options;int flag;tcgetattr(fd, &options);fcntl(fd, F_SETFL, 0);cfsetispeed(&options, BAUDRATE);cfsetospeed(&options, BAUDRATE);options.c_cflag |&#61; CREAD;/* Set to 8N1 */options.c_cflag &&#61; ~PARENB;options.c_cflag &&#61; ~CSTOPB;options.c_cflag &&#61; ~CSIZE;options.c_cflag |&#61; CS8; /* RAW */options.c_lflag &&#61; ~(ICANON | ECHO | ECHOE | ISIG); options.c_oflag &&#61; ~OPOST;/* For read data from printer */options.c_cc[VMIN] &#61; 0;options.c_cc[VTIME] &#61; 1; flag &#61; tcsetattr(fd, TCSANOW, &options);if (flag <0){perror("set_port: Setting port /dev/ttyS0 error - ");}
}
void close_port(int fd)
{close(fd);
}void print(int fd, char* sent)
{int len &#61; strlen(sent);char ToGB2312[100] &#61; {0x00};utf8_gb2312(sent,strlen(sent),ToGB2312,len); write(fd, &ToGB2312, strlen(ToGB2312));
}void print_line(int fd, char* sent)
{int len &#61; strlen(sent);char ToGB2312[100] &#61; {0x00};utf8_gb2312(sent,strlen(sent),ToGB2312,len); ToGB2312[strlen(ToGB2312)] &#61; 0x0a;write(fd, &ToGB2312, strlen(ToGB2312));
}//走纸
void feed(int fd, int num)
{unsigned char ch_feed &#61; 0x0a;int i;for (i&#61;0;i}//热敏打印机条码打印&#xff0c;输入的为数字
void barcode(int fd, char* bar)
{ char ins[3] &#61; {0x1d, 0x6b, 0x45}; //指令和条形码类型char hex_len[1]; //条形码长度hex_len[0] &#61; strlen(bar);char ToGB2312[50] &#61; {0x00};char all[100] &#61; {0x00};write(fd,&ins,strlen(ins));write(fd,&hex_len,1);utf8_gb2312(bar,strlen(bar),ToGB2312,strlen(bar)); write(fd,&ToGB2312,strlen(ToGB2312));
}int main(int argc, char *argv[])
{int fd, i;unsigned char convert[100] &#61; {0x00};fd &#61; open_port();set_port(fd);print(fd,"我爱中国\x0A");print_line(fd,"&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;");print(fd,"Acuity\x0a");barcode(fd,"1234567");print_line(fd,"1234567");feed(fd,5);close_port(fd);return 0;
}printf("iconv open failed!\n");perror("iconv_open");return -1;}memset(outbuf,0,outlen);if (iconv(cd,pin,(size_t*)&inlen,pout,(size_t*)&outlen) &#61;&#61; -1){printf("iconv failed!\n");perror("iconv");}iconv_close(cd);printf("out&#61; %s\n",&outbuf);return outbuf - old;
}int gb2312_utf8(char *inbuf,int inlen,char *outbuf,int outlen)
{return code_convert("gb2312","utf-8",inbuf,inlen,outbuf,outlen);
}int utf8_gb2312(char *inbuf,int inlen,char *outbuf,int outlen)
{return code_convert("utf-8","gb2312",inbuf,inlen,outbuf,outlen);
}int gb2312_ucs2(char *inbuf,int inlen,char *outbuf,int outlen)
{return code_convert("gb2312","ucs-2",inbuf,inlen,outbuf,outlen);
}int ucs2_gb2312(char *inbuf,int inlen,char *outbuf,int outlen)
{return code_convert("ucs-2","gb2312",inbuf,inlen,outbuf,outlen);
}int open_port()
{int fd; /* 端口文件描述符 */fd &#61; open(SERIAL_PORT, O_RDWR | O_NOCTTY | O_NDELAY);if (fd &#61;&#61; -1){perror("open_port: Unable to open /dev/ttyS0 - ");}return (fd);
}void set_port(int fd)
{struct termios options;int flag;tcgetattr(fd, &options);fcntl(fd, F_SETFL, 0);cfsetispeed(&options, BAUDRATE);cfsetospeed(&options, BAUDRATE);options.c_cflag |&#61; CREAD;/* Set to 8N1 */options.c_cflag &&#61; ~PARENB;options.c_cflag &&#61; ~CSTOPB;options.c_cflag &&#61; ~CSIZE;options.c_cflag |&#61; CS8; /* RAW */options.c_lflag &&#61; ~(ICANON | ECHO | ECHOE | ISIG); options.c_oflag &&#61; ~OPOST;/* For read data from printer */options.c_cc[VMIN] &#61; 0;options.c_cc[VTIME] &#61; 1; flag &#61; tcsetattr(fd, TCSANOW, &options);if (flag <0){perror("set_port: Setting port /dev/ttyS0 error - ");}
}
void close_port(int fd)
{close(fd);
}void print(int fd, char* sent)
{int len &#61; strlen(sent);char ToGB2312[100] &#61; {0x00};utf8_gb2312(sent,strlen(sent),ToGB2312,len); write(fd, &ToGB2312, strlen(ToGB2312));
}void print_line(int fd, char* sent)
{int len &#61; strlen(sent);char ToGB2312[100] &#61; {0x00};utf8_gb2312(sent,strlen(sent),ToGB2312,len); ToGB2312[strlen(ToGB2312)] &#61; 0x0a;write(fd, &ToGB2312, strlen(ToGB2312));
}//走纸
void feed(int fd, int num)
{unsigned char ch_feed &#61; 0x0a;int i;for (i&#61;0;i}//热敏打印机条码打印&#xff0c;输入的为数字
void barcode(int fd, char* bar)
{ char ins[3] &#61; {0x1d, 0x6b, 0x45}; //指令和条形码类型char hex_len[1]; //条形码长度hex_len[0] &#61; strlen(bar);char ToGB2312[50] &#61; {0x00};char all[100] &#61; {0x00};write(fd,&ins,strlen(ins));write(fd,&hex_len,1);utf8_gb2312(bar,strlen(bar),ToGB2312,strlen(bar)); write(fd,&ToGB2312,strlen(ToGB2312));
}int main(int argc, char *argv[])
{int fd, i;unsigned char convert[100] &#61; {0x00};fd &#61; open_port();set_port(fd);print(fd,"我爱中国\x0A");print_line(fd,"&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;");print(fd,"Acuity\x0a");barcode(fd,"1234567");print_line(fd,"1234567");feed(fd,5);close_port(fd);return 0;
}

 

插曲&#xff1a;在Linux执行该程序时&#xff0c;提示“invalid argument”&#xff0c;后面通过强大的CSDN解决【2】。

4.处理方法3

将第二种方法移植&#xff0c;修改为C&#43;&#43;描述&#xff0c;并置于Qt下&#xff0c;编译通过。但执行失败&#xff0c;在打开&#xff08;iconv_open&#xff09;iconv句柄时提示“invalid argument”&#xff0c;而此时的libc库已经更新&#xff0c;方法2可以成功执行&#xff0c;在Qt下为什么失败&#xff1f;&#xff1f;&#xff1f;继续换方法&#xff01;后面想想&#xff0c;Qt应该有相关封装好的编码转换函数&#xff0c;果不其然&#xff0c;真的有&#xff0c;后面就轻松实现了。关键代码如下&#xff0c;打印内容文件依然需要保存UTF-8格式保存&#xff0c;字符参数采用Qt QString格式&#xff0c;或者C&#43;&#43;的string都可以&#xff0c;比用C的char方便多了。

inline int UTF82GB2312(const QString &inStr,char *outbuf, int *outlen)
{QTextCodec *gbk &#61; QTextCodec::codecForName("GB2312");QTextCodec *utf8 &#61; QTextCodec::codecForName("UTF-8");char *p;QByteArray byte_utf &#61; gbk->fromUnicode(inStr);int byte_utf_size &#61; byte_utf.size();p &#61; byte_utf.data();while(byte_utf_size > 0){byte_utf_size --;*outbuf&#43;&#43; &#61; *p&#43;&#43;;}*outbuf &#61; 0;return 0;
}
//UTT-8 to GB2312
int peripherals::utf8_gb2312(char *inbuf, int inlen, char *outbuf, int outlen)
{return code_convert("utf-8","gb2312",inbuf,inlen,outbuf,outlen); //此方式为调用处理方法2中的函数&#xff0c;但执行失败。
}
//UTT-8 to GB2312
int peripherals::utf8_gb2312(QString &instr, char *outbuf, int *outlen)
{return UTF82GB2312(instr,outbuf,outlen);
}//UTT-8 to GB2312
int peripherals::utf8_gb2312(QString &instr, char *outbuf, int *outlen)
{return UTF82GB2312(instr,outbuf,outlen);
}


参考&#xff1a;

[1] http://blog.csdn.net/sealyao/article/details/5043138
[2] http://blog.csdn.net/violet089/article/details/51568667


推荐阅读
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 本文介绍了C函数ispunct()的用法及示例代码。ispunct()函数用于检查传递的字符是否是标点符号,如果是标点符号则返回非零值,否则返回零。示例代码演示了如何使用ispunct()函数来判断字符是否为标点符号。 ... [详细]
  • 本文介绍了PE文件结构中的导出表的解析方法,包括获取区段头表、遍历查找所在的区段等步骤。通过该方法可以准确地解析PE文件中的导出表信息。 ... [详细]
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • 预备知识可参考我整理的博客Windows编程之线程:https:www.cnblogs.comZhuSenlinp16662075.htmlWindows编程之线程同步:https ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 本文介绍了解决二叉树层序创建问题的方法。通过使用队列结构体和二叉树结构体,实现了入队和出队操作,并提供了判断队列是否为空的函数。详细介绍了解决该问题的步骤和流程。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • 猜字母游戏
    猜字母游戏猜字母游戏——设计数据结构猜字母游戏——设计程序结构猜字母游戏——实现字母生成方法猜字母游戏——实现字母检测方法猜字母游戏——实现主方法1猜字母游戏——设计数据结构1.1 ... [详细]
author-avatar
mobiledu2502910181
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有