Shapefile 是一种常用的矢量数据格式,保存了地理数据的坐标和属性信息。
ArcGIS 10.2.1之前,Shapefile的编码默认为本地编码,国内默认为GBK,这导致在导入国外提供的shp数据时会出现乱码。
Shapefile 在 .dbf 和 .cpg 中有存储编码页信息,可以通过解析这两个文件自动识别编码页,以修正乱码问题。
Shpfile构成
Shapefile 由多个文件构成,最基本的是 .shp 、.shx、.dbf 文件。
- .shp:存储地理数据的坐标信息。
- .shx:存储地理数据的位置索引,记录每个地理数据在shp文件中的位置,能够快速定位数据。
- .dbf:存储地理数据的属性信息,以dBase IV的数据表格式存储。
可选的文件如下:
- .shp.xml:以xml格式保存元数据。
- .prj:存储地理坐标系统和投影信息。
- .cpg:指定.dbf文件的字符编码。
- .sbn、.sbx:空间索引文件。
- .ixs:地理编码索引。
- .mxs:地理编码索引(ODB格式)。
- .atx:.dbf文件的属性索引。
dbf编码自动识别
.dbf 文件头结构如下:
.dbf 文件头中第29个字节(从0开始)表示Language driver ID,其代表的编码页参照以下链接:
http://shapelib.maptools.org/codepage.html?d=1563413688103
节选部分如下:
.cpg中明文存储文件编码,例如:windows-1251。
解析编码页时,优先使用.dbf中的Language Driver ID,若无则取.cpg文件中的编码。
c# 源码:
/// <summary>
/// 根据dbf中的Language Driver ID获取codepage,若没有则取.cpg文件中的编码
/// 代码页对照表:http://shapelib.maptools.org/codepage.html?d=1563413688103
/// </summary>
/// <param name="languageDriverID"></param>
/// <returns></returns>
private System.Text.Encoding GetEncoding(byte languageDriverID)
{
try
{
switch (languageDriverID)
{
case 0x00:
case 0x57:
// 0x00:读取cpg中的编码,若没有,则默认为utf-8
// 0x57:读取cpg中的编码,若没有,则windows默认为系统编码,android默认为utf-8
string cpgPath = Path.Combine(Path.GetDirectoryName(_fileName), Path.GetFileNameWithoutExtension(_fileName) + ".cpg");
if (File.Exists(cpgPath) == false)
{
if (languageDriverID == 0x00)
{
return Encoding.UTF8;
}
else
{
return Encoding.Default;
}
}
try
{
using (StreamReader sr = new StreamReader(cpgPath))
{
string txt = sr.ReadLine();
if (string.IsNullOrEmpty(txt))
{
if (languageDriverID == 0x00)
{
return Encoding.UTF8;
}
else
{
return Encoding.Default;
}
}
return Encoding.GetEncoding(txt);
}
}
catch (Exception ex)
{
if (languageDriverID == 0x00)
{
return Encoding.UTF8;
}
else
{
return Encoding.Default;
}
}
case 0x01:
case 0x09:
case 0x0B:
case 0x0D:
case 0x0F:
case 0x11:
case 0x15:
case 0x18:
case 0x19:
case 0x1B:
return Encoding.GetEncoding(437);//IBM437
case 0x02:
case 0x0A:
case 0x0E:
case 0x10:
case 0x12:
case 0x14:
case 0x16:
case 0x1A:
case 0x1D:
case 0x25:
case 0x37:
return Encoding.GetEncoding(850);//ibm850
case 0x03:
case 0x58:
case 0x59:
return Encoding.GetEncoding(1252);//Windows-1252
case 0x04:
return Encoding.GetEncoding(10000);//macintosh