为什么我按下图方式赋值,最后数组中的元素变为?了,不是很理解
事实上一个汉字由两个字符组成,所以实际上应该在数组里面是有6个有效字符的,尝试输出字符串就行了
这个文件读取成功与否,没有判断。
目标:从点阵字库LiShu56.txt文件中提取某一个汉字。
实现思路:通过汉字的gb2312机内码直接定位到文件中的该汉字起始位置,然后进行循环读写复制。
上图即该文件中的格式,为图方便,我直接使用二进制文件查看器,定义了几个基本的偏移量。
#define OFFSET_BASE 98 // 文件首基准位置
#define OFFSET_WORD 3666 // 这是点阵字库中每个字的整体字节量
#define OFFSET_INNER 13 // 这是单个字内部起始到实际字的数据的位置的偏移量
因为该字库文件中收录的字并不是直接从 a1a1 连续到 f7fe 的,所以不能够直接求偏移量然后直接偏移,否则使用 fseek 偏移超过文件指针允许的范围,程序将会陷入卡死(或死循环)的状态。
以下为算法流程图:
注释:
实现代码:
该文件基于Windows系统,在Windows系统中中文占用为两个字节(char),在Linux系统中为三个字节。
// 给单个字定位到指定位置
FILE* locateChar(char* text, FILE* src)
{
FILE* file = src;
fseek(file, OFFSET_BASE, SEEK_SET); // 设置起始位置
char reader[5];
char gbk[5];
getGBK(gbk, text); // 将汉字 text 的gbk码转为文本存储在gbk字符数组中
reader[4] = 0;
size_t size = sizeof(char);
for (int i = 0; i < 8178; i++) // 该字库收录了8178个简体汉字
{
fread(reader, size, 4, file);
if (strcmp(reader, gbk) == 0)
{
printf("Found char %s\n", reader);
fseek(file, OFFSET_INNER, SEEK_CUR);
break;
}
else
{
fseek(file, OFFSET_WORD, SEEK_CUR);
}
}
return file;
}
定位到汉字所在位置后就可以进行读取复制操作了。
FILE* file = fopen("bitmap.txt", "wb+");
FILE* src = fopen("LiShu56.txt", "rb");
src = locateChar(word, src); // 定位汉字
int tick = 56 * 56, flag; // 该字库点阵尺寸为 56×56,flag用于标记跳出循环
size_t size = sizeof(char);
char reader;
while (tick)
{
flag = 0;
while (fread(&reader, size, 1, src))
{
switch (reader)
{
case '_': case 'X':
fwrite(&reader, size, 1, file);
tick--;
break;
case '\r':
fwrite(&reader, size, 1, file);
break;
case '\n':
fwrite(&reader, size, 1, file);
flag = 1;
break;
default: break;
}
if (flag) break;
}
}
fclose(src);
fclose(file);
生成输出汉字“洋”示例:
命令窗口输出
Found char d1f3
文件输出
如果要将多个字合成在一个文件中,只需要稍作改动。
不过注意,将 FILE* 赋值给多个变量分别进行 fseek 定位,然后两个指针这里读几个字符,那里读几个字符,最后你会发现每个文件指针指向的都是最后一次调用 fseek 定位的那个字,导致最后是好几个一样的字合在一起。比如我要合成“洋伊”,最后得到的是:
Found char d1f3
Found char d2c1
抽象点说,简而言之,就是指向文件内容位置的文件指针是唯一的。
如果要将多个字合成在一个文本中,可以采用以下思路:
先将要合成的字,每个字存在一个临时文件中,再依次打开这些文件,读取并复制到(合成)同一文件中。