解決Java中基于GeoTools的Shapefile讀取亂碼的問(wèn)題
前言
文件編碼(File Encoding)是指文件在計(jì)算機(jī)中存儲(chǔ)時(shí)所使用的字符編碼方式。字符編碼是將字符(如字母、數(shù)字、標(biāo)點(diǎn)符號(hào)等)轉(zhuǎn)換成計(jì)算機(jī)可以直接存儲(chǔ)和處理的數(shù)字或二進(jìn)制代碼的過(guò)程。不同的編碼方式?jīng)Q定了文件中字符如何被表示和存儲(chǔ),以及這些字符如何被不同的軟件或系統(tǒng)正確地讀取和顯示。在進(jìn)行空間數(shù)據(jù)處理的時(shí)候,通常會(huì)涉及大量的空間數(shù)據(jù),為了更加詳細(xì)且準(zhǔn)確的描述這些空間數(shù)據(jù),我們通過(guò)會(huì)配置一些屬性數(shù)據(jù)。
Shapefile屬性字段的編碼通常指的是存儲(chǔ)在shapefile的dbf(數(shù)據(jù)庫(kù)文件)中的屬性數(shù)據(jù)的字符編碼方式。Shapefile是一種用于存儲(chǔ)地理空間數(shù)據(jù)的文件格式,它由多個(gè)文件組成,其中dbf文件用于存儲(chǔ)每個(gè)幾何形狀的屬性數(shù)據(jù)。

1、Shapefile屬性字段編碼的情況:
默認(rèn)編碼:
在不同的軟件或庫(kù)中,shapefile的默認(rèn)編碼可能有所不同。例如,ArcGIS Desktop在較新版本(如10.2.1及以后)中,shapefile (.DBF) 的編碼頁(yè)的默認(rèn)設(shè)置為UTF-8(UNICODE)。而在一些其他軟件或庫(kù)中,如Java GDAL庫(kù),默認(rèn)可能使用ISO-8859-1編碼,這會(huì)導(dǎo)致中文等非西歐字符出現(xiàn)亂碼問(wèn)題。
編碼設(shè)置:
在使用某些軟件或庫(kù)處理shapefile時(shí),可以通過(guò)設(shè)置來(lái)改變屬性字段的編碼方式。例如,在Java GDAL庫(kù)中,可以通過(guò)調(diào)GDAL.SetConfigOption("SHAPE_ENCODING","UTF-8")來(lái)設(shè)置GDAL庫(kù)的默認(rèn)編碼為UTF-8,從而避免中文屬性亂碼的問(wèn)題。在ArcGIS中,雖然默認(rèn)編碼可能是UTF-8,但也可以通過(guò)修改注冊(cè)表中的dbfDefault值來(lái)指定不同的編碼方式。不過(guò),這種方法主要影響ArcGIS Desktop生成的shapefile和dBASE文件的編碼類型,且僅對(duì)ArcGIS Desktop生效。
編碼轉(zhuǎn)換:
如果已經(jīng)存在編碼不匹配的shapefile文件,可能需要通過(guò)編碼轉(zhuǎn)換工具來(lái)修改其屬性字段的編碼方式。例如,可以使用FME Workbench等GIS數(shù)據(jù)轉(zhuǎn)換工具來(lái)轉(zhuǎn)換shapefile的編碼。也可以使用編程方式,如利用geotools等庫(kù)來(lái)讀取原始編碼的shapefile文件,并以新的編碼方式重新寫入數(shù)據(jù),從而實(shí)現(xiàn)編碼的轉(zhuǎn)換。
注意事項(xiàng)
在處理shapefile屬性字段編碼時(shí),需要確保整個(gè)處理流程中的編碼方式一致,以避免出現(xiàn)亂碼或數(shù)據(jù)丟失等問(wèn)題。如果shapefile文件是從不同來(lái)源獲取的,可能需要先確認(rèn)其編碼方式,以便在后續(xù)處理中正確讀取和寫入數(shù)據(jù)。在進(jìn)行編碼轉(zhuǎn)換時(shí),應(yīng)謹(jǐn)慎操作,以免損壞原始數(shù)據(jù)。建議在轉(zhuǎn)換前備份原始文件,并在轉(zhuǎn)換后進(jìn)行驗(yàn)證以確保數(shù)據(jù)的完整性和準(zhǔn)確性。
本文主要講述使用Java編程語(yǔ)言進(jìn)行地理信息數(shù)據(jù)解析的時(shí)候,遇到Shapefile的屬性信息亂碼的幾種情況,以及根據(jù)不同的編碼設(shè)置來(lái)進(jìn)行屬性信息的解析。博文首先介紹采用不同的字符集編碼的shapefile文件,然后在Qgis中打開屬性表,查看相關(guān)的字符展示情況,接著說(shuō)明在Java當(dāng)中調(diào)用Geotools時(shí),為經(jīng)過(guò)字符編碼處理和經(jīng)過(guò)字符編碼處理后的對(duì)比,讓大家熟悉在Geotools的開發(fā)過(guò)程中,掌握字符編碼的設(shè)置。
一、Shp文件常見的字符集編碼
為了講解使用不同的編碼來(lái)展示空間數(shù)據(jù),我們首先來(lái)介紹基礎(chǔ)的數(shù)據(jù),即三份不同的空間數(shù)據(jù)格式,其格式都是shapefile的。但是在不同的空間記錄中,其字段的值是采用不同的編碼的。在這里,采用QGIS這款軟件來(lái)進(jìn)行屬性數(shù)據(jù)的展示,方便大家了解日常中的數(shù)據(jù)展示。
1、System編碼
第一種要介紹的就是System的編碼方式,這里采用的是用我國(guó)的Lake圖層信息,首先我們?cè)赒gis中打開這份數(shù)據(jù)來(lái)看一下,文件的本地路徑為:
F:\vector_data\地理數(shù)據(jù)20240912\地理數(shù)據(jù)20240912\水系河流\1 全國(guó)1-5級(jí)標(biāo)準(zhǔn)河流-wgs84\主要湖泊面文件\Lake.shp
將數(shù)據(jù)在Qgis軟件中打開可以看到其主要的源信息描述如下:

可以在編碼一欄中看到,這份文件的編碼是System的。 為了看到其里面的屬性信息,可以右鍵點(diǎn)擊shp數(shù)據(jù),點(diǎn)擊打開屬性表就可以看到這份數(shù)據(jù)的完整的數(shù)據(jù)信息,打開后相關(guān)信息如下所示:

在上圖的紅線框中很明顯可以看到,有一列叫NAME的,它的值是有亂碼的,并沒(méi)有是我們常見的編碼。 因此這算是亂碼的第一種情況。
2、ISO-8859-1編碼
第二種也是常見的ISO-8859-1編碼,這里準(zhǔn)備的數(shù)據(jù)是一份湖南省的鄉(xiāng)鎮(zhèn)邊界數(shù)據(jù),其在文件磁盤中目錄如下,:
C:\BaiduDownload\湖南省\湖南省_鄉(xiāng)鎮(zhèn)邊界.shp
同樣的,我們使用QGis軟件打開上面的鄉(xiāng)鎮(zhèn)邊界.shp文件,打開后可以看到很明確的字符編碼信息:

同樣的我們使用QGIS來(lái)進(jìn)行屬性數(shù)據(jù)的打開查看, 詳細(xì)如下圖所示:

3、UTF-8編碼
這應(yīng)該算是比較標(biāo)準(zhǔn)的編碼方式,如果進(jìn)行數(shù)據(jù)制作的時(shí)候,都是統(tǒng)一采用UTF-8的模式,那么這種方式無(wú)疑是最好的,估計(jì)也不存在字符編碼的問(wèn)題了。

這個(gè)時(shí)候,在QGIS中打開屬性表,其屬性字段的內(nèi)容是正??梢灾苯宇A(yù)覽的,詳情如下圖所示。

當(dāng)然,字符編碼的處理方式根據(jù)項(xiàng)目的不同,也會(huì)有不同的設(shè)置,種類繁多,不甚枚舉,這里僅以這幾項(xiàng)為例作為例子來(lái)講解,如果以后在開發(fā)過(guò)程中,遇到這種情況,可以根據(jù)實(shí)際來(lái)進(jìn)行編碼的擴(kuò)充和修復(fù)。
二、GeoTools解析實(shí)戰(zhàn)
在上面的一節(jié)中,我們簡(jiǎn)單的對(duì)三種不同的編碼方式的shapefile文件進(jìn)行了簡(jiǎn)單的介紹,本節(jié)則重點(diǎn)介紹如何使用Java開發(fā)語(yǔ)言,使用GeoTools的開發(fā)組件進(jìn)行編碼的處理和轉(zhuǎn)換,將屬性數(shù)據(jù)可以成功讀取到我們的應(yīng)用程序中。在這里需要統(tǒng)一說(shuō)明的是,在進(jìn)行數(shù)據(jù)的處理和轉(zhuǎn)換的時(shí)候,為了進(jìn)行數(shù)據(jù)的演示,我們僅將數(shù)據(jù)的前10行數(shù)據(jù)記載處理,這樣如果有亂碼的問(wèn)題,我們就可以直接進(jìn)行干預(yù),通過(guò)修改其它的字符集函數(shù)的方式來(lái)保證文字的識(shí)別與處理。
1、未進(jìn)行字符處理
首先我們來(lái)加載UTF-8的矢量數(shù)據(jù),測(cè)試一下使用UTF-8的情況下,如何使用GeoTools的方法來(lái)進(jìn)行屬性表格的解析。下面來(lái)看如何使用GeoTools來(lái)進(jìn)行空間屬性數(shù)據(jù)的解析與展示,關(guān)鍵代碼如下所示:
/**
* * 不做任何處理展示shp文件數(shù)據(jù)詳情
*
* @param shpFile shp文件地址
* @throws Exception
*/
protected static void showShpDetails(String shpFile) throws Exception {
File file = new File(shpFile);
if (!file.exists()) {
System.out.println("文件不存在");
return;
}
ShapefileDataStore store = new ShapefileDataStore(file.toURI().toURL());
String typeName = store.getTypeNames()[0];
// 創(chuàng)建一個(gè)Query對(duì)象
Query query = new Query(typeName);
// 設(shè)置查詢返回的最大特征數(shù)為10
query.setMaxFeatures(10);
SimpleFeatureSource featureSource = store.getFeatureSource();
// 執(zhí)行查詢
SimpleFeatureCollection simpleFeatureCollection = featureSource.getFeatures(query);
SimpleFeatureIterator itertor = simpleFeatureCollection.features();
// 遍歷featurecollection
while (itertor.hasNext()) {
SimpleFeature feature = itertor.next();
Collection<Property> p = feature.getProperties();
Iterator<Property> it = p.iterator();
// 遍歷feature的properties
while (it.hasNext()) {
Property pro = it.next();
if (null != pro && null != pro.getValue()) {
String field = pro.getName().toString();
String value = pro.getValue().toString();
System.out.println(field + "===" + value);
}
}
System.out.println("-----------------------------------------------------");
}
}在上面的代碼中,需要注意的地方就是,我們想要在查詢的時(shí)候只查10條,那么就需要使用到GeoTools的查詢Query對(duì)象,通過(guò)結(jié)合Query對(duì)象來(lái)實(shí)現(xiàn)只查10條。10條的設(shè)置是個(gè)經(jīng)驗(yàn)值,可以根據(jù)服務(wù)器的速度和性能來(lái)進(jìn)行平衡,可以一次處理更多的數(shù)據(jù)。運(yùn)行測(cè)試用例來(lái)看其讀取的結(jié)果如下:

可以看到,在IDE的控制臺(tái)中,讀取出來(lái)的空間屬性信息都是亂碼。
2、亂碼問(wèn)題的解決
要想解決亂碼的問(wèn)題,首先要找到根源。我們需要對(duì)屬性信息字段進(jìn)行字符集編碼的控制。因此我們?cè)诨ヂ?lián)網(wǎng)上查詢一下,時(shí)候有相應(yīng)的方案。在這里哪怕不管具體的方案,也要了解為什么會(huì)出現(xiàn)這個(gè)問(wèn)題。我們來(lái)看下ShapefileDataStore這個(gè)對(duì)象,這個(gè)對(duì)象是有一個(gè)關(guān)于字符集的編碼的,如下所示:

如果看過(guò)源碼的話,各位小伙伴會(huì)發(fā)現(xiàn),在GeoTools中有默認(rèn)的編碼集,即:Charset charset = DEFAULT_STRING_CHARSET;
public static final Charset DEFAULT_STRING_CHARSET =
(Charset) ShapefileDataStoreFactory.DBFCHARSET.getDefaultValue();其實(shí)現(xiàn)的實(shí)際邏輯代碼如下:
/**
* Optional - character used to decode strings from the DBF file. If none is provided, the
* factory will instruct {@link ShapefileDataStore} to try to guess a charset from CPG file,
* before using a default value.
*
* @see ShapefileDataStore#setTryCPGFile(boolean)
*/
public static final Param DBFCHARSET =
new Param(
"charset",
Charset.class,
"character used to decode strings from the DBF file",
false,
StandardCharsets.ISO_8859_1,
new KVP(Param.LEVEL, "advanced")) {
/*
* This is an example of a non simple Param type where a custom parse method is required.
*
* @see org.geotools.data.DataStoreFactorySpi.Param#parse(java.lang.String)
*/
@Override
public Object parse(String text) throws IOException {
return Charset.forName(text);
}
@Override
public String text(Object value) {
return ((Charset) value).name();
}
};通過(guò)上面的代碼可以看到,這里使用的默認(rèn)編碼是:StandardCharsets.ISO_8859_1,也就是ISO-8859-1的方式。
3、轉(zhuǎn)碼支持
了解了亂碼的產(chǎn)生原理之后,我們來(lái)進(jìn)行相應(yīng)的代碼轉(zhuǎn)換,關(guān)于編碼的轉(zhuǎn)換有兩種方式,第一種統(tǒng)一在Store一層就進(jìn)行轉(zhuǎn)碼。這樣比較單一,也比較簡(jiǎn)單。第二種就是在每一個(gè)value中進(jìn)行編程式轉(zhuǎn)碼,這樣不僅麻煩,而且效率低。為了支持全局處理編碼等,我們將函數(shù)進(jìn)行已統(tǒng)一的封裝,增加了自定義編碼的支持:
/**
* *展示shp文件數(shù)據(jù)詳情
*
* @param shpFile shp文件地址
* @param unifySetting 是否統(tǒng)一設(shè)置字符
* @param chartSet 需要設(shè)置的字符編碼
* @throws Exception
*/
protected static void showShpDetails(String shpFile, boolean unifySetting, String chartSet) throws Exception {
File file = new File(shpFile);
if (!file.exists()) {
System.out.println("文件不存在");
return;
}
ShapefileDataStore store = new ShapefileDataStore(file.toURI().toURL());
String typeName = store.getTypeNames()[0];
// 創(chuàng)建一個(gè)Query對(duì)象
Query query = new Query(typeName);
// 設(shè)置查詢返回的最大特征數(shù)為10
query.setMaxFeatures(10);
if (unifySetting) {
store.setCharset(Charset.forName(chartSet));// 設(shè)置中文字符編碼
}
SimpleFeatureSource featureSource = store.getFeatureSource();
System.out.println(featureSource);
// 執(zhí)行查詢
SimpleFeatureCollection simpleFeatureCollection = featureSource.getFeatures(query);
SimpleFeatureIterator itertor = simpleFeatureCollection.features();
// 遍歷featurecollection
while (itertor.hasNext()) {
SimpleFeature feature = itertor.next();
Collection<Property> p = feature.getProperties();
Iterator<Property> it = p.iterator();
// 遍歷feature的properties
while (it.hasNext()) {
Property pro = it.next();
if (null != pro && null != pro.getValue()) {
String field = pro.getName().toString();
String value = pro.getValue().toString();
if (!unifySetting) {
// byte[]bytes= value.getBytes("iso8859-1");
byte[] bytes = value.getBytes();
value = new String(bytes, chartSet);
}
System.out.println(field + "===" + value);
}
}
System.out.println("-------------------------------------------------------------");
}
}4、屬性字段編碼結(jié)果
下面對(duì)集中情況的屬性數(shù)據(jù)進(jìn)行解析,將輸出的成果在編輯器的控制臺(tái)進(jìn)行綜合展示。

可以在控制臺(tái)中看到以下的數(shù)據(jù)都是正常的,
org.geotools.data.shapefile.ShapefileFeatureStore@1b6e1eff the_geom===POINT (113.24947489555838 28.625229546432124) 名稱===南門橋(公交站) 大類===交通設(shè)施服務(wù) 中類===公交車站 小類===公交車站相關(guān) 地址===星通2路 省===湖南省 市===長(zhǎng)沙市 區(qū)===長(zhǎng)沙縣 WGS84_經(jīng)===113.249474896 WGS84_緯===28.6252295464
同理,其它的數(shù)據(jù)如湖南省鄉(xiāng)鎮(zhèn)邊界數(shù)據(jù),我們使用編碼后來(lái)查看具體的輸出。

同樣的,在控制臺(tái)中可以看到以下的輸出,
gml_id===layer_township_pg.15847
Name===星子鎮(zhèn)
layer===鄉(xiāng)鎮(zhèn)
code===441882101000
grade===4
----------------------------------------------------------------------
gml_id===layer_township_pg.15849
Name===三水瑤族鄉(xiāng)
layer===鄉(xiāng)鎮(zhèn)
code===441882201000
grade===4
同樣的,編碼方式是ISO-8859-1的數(shù)據(jù)經(jīng)過(guò)編碼后正常顯示。 到此,使用Java語(yǔ)言進(jìn)行GeoTools解析Shp文件的屬性信息時(shí)亂碼的問(wèn)題得到解決。
三、總結(jié)
以上就是本文的主要內(nèi)容,本文主要講述使用Java編程語(yǔ)言進(jìn)行地理信息數(shù)據(jù)解析的時(shí)候,遇到Shapefile的屬性信息亂碼的幾種情況,以及根據(jù)不同的編碼設(shè)置來(lái)進(jìn)行屬性信息的解析。博文首先介紹采用不同的字符集編碼的shapefile文件,然后在Qgis中打開屬性表,查看相關(guān)的字符展示情況,接著說(shuō)明在Java當(dāng)中調(diào)用Geotools時(shí),為經(jīng)過(guò)字符編碼處理和經(jīng)過(guò)字符編碼處理后的對(duì)比,讓大家熟悉在Geotools的開發(fā)過(guò)程中,掌握字符編碼的設(shè)置。行文倉(cāng)促,定有許多不足之處,如有不當(dāng)之處,還懇請(qǐng)各位專家和博主在評(píng)論區(qū)留言支持,不勝感激。
博文在寫作過(guò)程中,參考以下,在此表示表示:
2、java gdal 創(chuàng)建shapefile屬性中文亂碼。
到此這篇關(guān)于在Java中基于GeoTools的Shapefile讀取亂碼的問(wèn)題解決辦法的文章就介紹到這了,更多相關(guān)Java GeoTools的Shapefile讀取亂碼內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 基于Java和GeoTools的Shapefile矢量數(shù)據(jù)縮略圖生成實(shí)踐
- Java利用Geotools實(shí)現(xiàn)不同坐標(biāo)系之間坐標(biāo)轉(zhuǎn)換
- Java?使用geotools讀取tiff數(shù)據(jù)的示例代碼
- java使用GeoTools讀取shp文件并畫圖的操作代碼
- JAVA使用geotools讀取shape格式文件的方法
- 在Java中使用ModelMapper簡(jiǎn)化Shapefile屬性轉(zhuǎn)JavaBean實(shí)戰(zhàn)過(guò)程
- Java用GDAL讀寫shapefile的方法示例
相關(guān)文章
Java并發(fā)J.U.C并發(fā)容器類list set queue
SpringBoot中web模版數(shù)據(jù)渲染展示的案例詳解
java文件復(fù)制代碼片斷(java實(shí)現(xiàn)文件拷貝)
SpringCloud項(xiàng)目中Feign組件添加請(qǐng)求頭所遇到的坑及解決
Java super關(guān)鍵字調(diào)用父類過(guò)程解析
Java的MyBatis快速入門和實(shí)戰(zhàn)詳解
SpringBoot3.X配置OAuth的代碼實(shí)踐

