如何通过Windows API在Alaska Xbase++中判断TXT文件编码类型
在Alaska Xbase++中调用Windows API判断TXT文件编码类型
核心判断逻辑
文件编码的识别主要依赖字节序标记(BOM)和字节特征:
- UTF-16(LE):文件开头为
FF FE字节序列 - UTF-16(BE):文件开头为
FE FF字节序列 - UTF-8(带BOM):文件开头为
EF BB BF字节序列 - UTF-8(无BOM):需通过多字节序列规则判断(如
110xxxxx开头的字节后需跟10xxxxxx格式的字节) - ANSI:无BOM,以单字节为主,扩展ASCII范围(0x80-0xFF)无UTF-8的多字节规律
Xbase++调用Windows API实现步骤
Xbase++通过DLLFUNCTION声明Windows API函数,读取文件头字节完成编码判断,核心用到CreateFileA、ReadFile、CloseHandle三个API。
1. 声明Windows API及常量
在代码开头添加以下声明:
DLLFUNCTION CreateFileA( cFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile ) AS LONG PASCAL FROM "CreateFileA" IN "kernel32.dll" DLLFUNCTION ReadFile( hFile, @lpBuffer, nNumberOfBytesToRead, @lpNumberOfBytesRead, lpOverlapped ) AS LOGIC PASCAL FROM "ReadFile" IN "kernel32.dll" DLLFUNCTION CloseHandle( hObject ) AS LOGIC PASCAL FROM "CloseHandle" IN "kernel32.dll" // 定义API所需常量 #define GENERIC_READ 0x80000000 #define FILE_SHARE_READ 0x00000001 #define OPEN_EXISTING 3 #define FILE_ATTRIBUTE_NORMAL 0x80
2. 编写编码判断主函数
实现GetFileEncoding()函数,接收文件路径返回编码类型:
FUNCTION GetFileEncoding( cFilePath ) LOCAL hFile, nBytesRead, cBuffer := Space(4), cEncoding := "ANSI" // 打开目标文件 hFile := CreateFileA( cFilePath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 ) IF hFile == -1 RETURN "无法打开文件" ENDIF // 读取文件前4个字节 IF ReadFile( hFile, @cBuffer, 4, @nBytesRead, 0 ) IF nBytesRead >= 2 // 判断UTF-16 LE BOM IF Asc(SubStr(cBuffer,1,1)) == 0xFF .AND. Asc(SubStr(cBuffer,2,1)) == 0xFE cEncoding := "UTF-16 LE" // 判断UTF-16 BE BOM ELSEIF Asc(SubStr(cBuffer,1,1)) == 0xFE .AND. Asc(SubStr(cBuffer,2,1)) == 0xFF cEncoding := "UTF-16 BE" // 判断UTF-8 BOM ELSEIF nBytesRead >=3 .AND. Asc(SubStr(cBuffer,1,1)) == 0xEF .AND. Asc(SubStr(cBuffer,2,1)) == 0xBB .AND. Asc(SubStr(cBuffer,3,1)) == 0xBF cEncoding := "UTF-8 (带BOM)" // 无BOM时判断UTF-8或ANSI ELSE cEncoding := IsUtf8WithoutBOM( cBuffer, nBytesRead ) ? "UTF-8 (无BOM)" : "ANSI" ENDIF ENDIF ENDIF // 关闭文件句柄 CloseHandle( hFile ) RETURN cEncoding
3. 辅助函数:判断无BOM的UTF-8
通过字节序列规则识别无BOM的UTF-8:
FUNCTION IsUtf8WithoutBOM( cBuffer, nBytesRead ) LOCAL i, nByte, nBytesToFollow, lIsUtf8 := .T. FOR i := 1 TO nBytesRead nByte := Asc(SubStr(cBuffer,i,1)) IF nByte < 0x80 // 单字节ASCII,跳过 LOOP ELSEIF (nByte & 0xE0) == 0xC0 // 双字节UTF-8,需1个后续字节 nBytesToFollow := 1 ELSEIF (nByte & 0xF0) == 0xE0 // 三字节UTF-8,需2个后续字节 nBytesToFollow := 2 ELSEIF (nByte & 0xF8) == 0xF0 // 四字节UTF-8,需3个后续字节 nBytesToFollow := 3 ELSE // 无效UTF-8起始字节 lIsUtf8 := .F. EXIT ENDIF // 检查后续字节是否符合10xxxxxx格式 FOR j := 1 TO nBytesToFollow i++ IF i > nBytesRead lIsUtf8 := .F. EXIT ENDIF nByte := Asc(SubStr(cBuffer,i,1)) IF (nByte & 0xC0) != 0x80 lIsUtf8 := .F. EXIT ENDIF NEXT j IF !lIsUtf8 EXIT ENDIF NEXT i RETURN lIsUtf8
4. 调用示例
LOCAL cTargetFile := "C:\example.txt" LOCAL cFileEncoding := GetFileEncoding( cTargetFile ) ? "文件编码类型:", cFileEncoding
注意事项
- 无BOM的纯ASCII文件会被识别为UTF-8(因为ASCII是UTF-8的子集),这是正常现象。
- 仅读取文件前4个字节,无需加载整个文件,保证效率。
- 确保程序拥有目标文件的读取权限。
内容的提问来源于stack exchange,提问作者EngiDev
相关产品推荐
相关产品推荐

