如何逐行阅读unicode(utf-8)/二进制文件

嗨程序员,

我想逐行读一个由记事本创build的Unicode(UTF-8)文本文件,我不想在屏幕上显示Unicodestring,我只想读取和比较string!

此代码逐行读取ANSI文件,并比较string

我想要的是

逐行阅读test_ansi.txt

如果该行=“b”打印“YES!”

否则打印“不!

read_ansi_line_by_line.c

#include <stdio.h> int main() { char *inname = "test_ansi.txt"; FILE *infile; char line_buffer[BUFSIZ]; /* BUFSIZ is defined if you include stdio.h */ char line_number; infile = fopen(inname, "r"); if (!infile) { printf("\nfile '%s' not found\n", inname); return 0; } printf("\n%s\n\n", inname); line_number = 0; while (fgets(line_buffer, sizeof(line_buffer), infile)) { ++line_number; /* note that the newline is in the buffer */ if (strcmp("b\n", line_buffer) == 0 ){ printf("%d: YES!\n", line_number); }else{ printf("%d: NO!\n", line_number,line_buffer); } } printf("\n\nTotal: %d\n", line_number); return 0; } 

test_ansi.txt

 a b c 

编译

 gcc -o read_ansi_line_by_line read_ansi_line_by_line.c 

产量

 test_ansi.txt 1: NO! 2: YES! 3: NO! Total: 3 

现在我需要阅读由记事本创build的Unicode(UTF-8)文件,超过6个月后,我没有发现在C中的任何好的代码/库可以读取UTF-8编码的文件!我不知道为什么,但是我认为标准C不支持Unicode!

阅读Unicode二进制文件的确定!,但问题是二进制文件大部分已经在二进制模式下创build,这意味着如果我们想要读一个由记事本创build的Unicode(UTF-8)文件,我们需要将它从UTF-8文件到BINARY文件!

此代码将Unicodestring写入二进制文件,注意C文件以UTF-8编码并由GCC编译

我想要的是

将Unicode字符“ب”写入test_bin.dat

create_bin.c

 #define UNICODE #ifdef UNICODE #define _UNICODE #else #define _MBCS #endif #include <stdio.h> #include <wchar.h> int main() { /*Data to be stored in file*/ wchar_t line_buffer[BUFSIZ]=L"ب"; /*Opening file for writing in binary mode*/ FILE *infile=fopen("test_bin.dat","wb"); /*Writing data to file*/ fwrite(line_buffer, 1, 13, infile); /*Closing File*/ fclose(infile); return 0; } 

编译

 gcc -o create_bin create_bin.c 

产量

 create test_bin.dat 

现在我想要逐行读取二进制文件并进行比较!

我想要的是

如果line =“ب”print“YES!”,请逐行阅读test_bin.dat。 否则打印“不!

read_bin_line_by_line.c

 #define UNICODE #ifdef UNICODE #define _UNICODE #else #define _MBCS #endif #include <stdio.h> #include <wchar.h> int main() { wchar_t *inname = L"test_bin.dat"; FILE *infile; wchar_t line_buffer[BUFSIZ]; /* BUFSIZ is defined if you include stdio.h */ infile = _wfopen(inname,L"rb"); if (!infile) { wprintf(L"\nfile '%s' not found\n", inname); return 0; } wprintf(L"\n%s\n\n", inname); /*Reading data from file into temporary buffer*/ while (fread(line_buffer,1,13,infile)) { /* note that the newline is in the buffer */ if ( wcscmp ( L"ب" , line_buffer ) == 0 ){ wprintf(L"YES!\n"); }else{ wprintf(L"NO!\n", line_buffer); } } /*Closing File*/ fclose(infile); return 0; } 

产量

 test_bin.dat YES! 

问题

这个方法非常长! 和不强大(软件工程初学者)

请任何一个知道如何阅读Unicode文件? (我知道它不容易!)请任何一个知道如何将Unicode文件转换为二进制文件? (简单的方法)请任何一个知道如何在二进制模式下读取Unicode文件? (我不确定)

谢谢。

Solutions Collecting From Web of "如何逐行阅读unicode(utf-8)/二进制文件"

UTF-8的一个不错的属性是你不需要解码就可以比较它。 不管你先解码还是不解码,从strcmp返回的顺序都是一样的。 所以只要读取它作为原始字节并运行strcmp。

我找到了解决我的问题的方法,并且希望将解决方案分享给任何有兴趣阅读C99中的UTF-8文件的人。

 void ReadUTF8(FILE* fp) { unsigned char iobuf[255] = {0}; while( fgets((char*)iobuf, sizeof(iobuf), fp) ) { size_t len = strlen((char *)iobuf); if(len > 1 && iobuf[len-1] == '\n') iobuf[len-1] = 0; len = strlen((char *)iobuf); printf("(%d) \"%s\" ", len, iobuf); if( iobuf[0] == '\n' ) printf("Yes\n"); else printf("No\n"); } } void ReadUTF16BE(FILE* fp) { } void ReadUTF16LE(FILE* fp) { } int main() { FILE* fp = fopen("test_utf8.txt", "r"); if( fp != NULL) { // see http://en.wikipedia.org/wiki/Byte-order_mark for explaination of the BOM // encoding unsigned char b[3] = {0}; fread(b,1,2, fp); if( b[0] == 0xEF && b[1] == 0xBB) { fread(b,1,1,fp); // 0xBF ReadUTF8(fp); } else if( b[0] == 0xFE && b[1] == 0xFF) { ReadUTF16BE(fp); } else if( b[0] == 0 && b[1] == 0) { fread(b,1,2,fp); if( b[0] == 0xFE && b[1] == 0xFF) ReadUTF16LE(fp); } else { // we don't know what kind of file it is, so assume its standard // ascii with no BOM encoding rewind(fp); ReadUTF8(fp); } } fclose(fp); } 

如果您使用Visual Studio 2005及更高版本,则fgets()可以解码UTF-8编码的文件。 像这样改变你的代码:

 infile = fopen(inname, "r, ccs=UTF-8"); 

我知道我不好…但是你甚至不考虑BOM! 这里大多数例子都会失败。

编辑:

字节顺序标记是文件初始位置的几个字节,可以用来标识文件的编码。 一些编辑添加它们,很多时候他们只是以拙劣的方式破坏事情(我记得因为这个问题,我们花了几分钟时间来处理一个PHP头文件的问题)。

一些RTFM: http : //en.wikipedia.org/wiki/Byte_order_mark http://blogs.msdn.com/oldnewthing/archive/2004/03/24/95235.aspx 什么是XML BOM,我如何检测它?

在这篇文章中编写了一个编码和解码例程,并解释了unicode是如何编码的:

http://www.codeguru.com/cpp/misc/misc/multi-lingualsupport/article.php/c10451/

它可以很容易地调整为C.简单地编码您的ANSI或解码UTF-8字符串并进行字节比较

编辑:OP后说,这是很难从C ++重写函数在这里模板:

需要什么:
+释放分配的内存(或等到进程结束或忽略)
+添加4个字节的功能
+告诉我,short和int不能保证是2和4字节长(我知道,但C真的很愚蠢!),最后
+找到一些其他的错误

 #include <stdlib.h> #include <string.h> #define MASKBITS 0x3F #define MASKBYTE 0x80 #define MASK2BYTES 0xC0 #define MASK3BYTES 0xE0 #define MASK4BYTES 0xF0 #define MASK5BYTES 0xF8 #define MASK6BYTES 0xFC char* UTF8Encode2BytesUnicode(unsigned short* input) { int size = 0, cindex = 0; while (input[size] != 0) size++; // Reserve enough place; The amount of char* result = (char*) malloc(size); for (int i=0; i<size; i++) { // 0xxxxxxx if(input[i] < 0x80) { result[cindex++] = ((char) input[i]); } // 110xxxxx 10xxxxxx else if(input[i] < 0x800) { result[cindex++] = ((char)(MASK2BYTES | input[i] >> 6)); result[cindex++] = ((char)(MASKBYTE | input[i] & MASKBITS)); } // 1110xxxx 10xxxxxx 10xxxxxx else if(input[i] < 0x10000) { result[cindex++] = ((char)(MASK3BYTES | input[i] >> 12)); result[cindex++] = ((char)(MASKBYTE | input[i] >> 6 & MASKBITS)); result[cindex++] = ((char)(MASKBYTE | input[i] & MASKBITS)); } } } wchar_t* UTF8Decode2BytesUnicode(char* input) { int size = strlen(input); wchar_t* result = (wchar_t*) malloc(size*sizeof(wchar_t)); int rindex = 0, windex = 0; while (rindex < size) { wchar_t ch; // 1110xxxx 10xxxxxx 10xxxxxx if((input[rindex] & MASK3BYTES) == MASK3BYTES) { ch = ((input[rindex] & 0x0F) << 12) | ( (input[rindex+1] & MASKBITS) << 6) | (input[rindex+2] & MASKBITS); rindex += 3; } // 110xxxxx 10xxxxxx else if((input[rindex] & MASK2BYTES) == MASK2BYTES) { ch = ((input[rindex] & 0x1F) << 6) | (input[rindex+1] & MASKBITS); rindex += 2; } // 0xxxxxxx else if(input[rindex] < MASKBYTE) { ch = input[rindex]; rindex += 1; } result[windex] = ch; } } char* getUnicodeToUTF8(wchar_t* myString) { int size = sizeof(wchar_t); if (size == 1) return (char*) myString; else if (size == 2) return UTF8Encode2BytesUnicode((unsigned short*) myString); else return UTF8Encode4BytesUnicode((unsigned int*) myString); } 

只是为了解决BOM的论点。 这是从记事本文件

  [paul@paul-es5 tests]$ od -t x1 /mnt/hgfs/cdrive/test.txt 0000000 ef bb bf 61 0d 0a 62 0d 0a 63 0000012 

在开始时有一个BOM

就个人而言,我不认为应该有一个BOM(因为它是一个字节格式),但那不是重点