Bootstrap

Ubuntu下使用CMake编译安装GDAL3.6.1(3.8.4)、链接Java(Java21)、加入FileGDB驱动

Ubuntu下使用CMake编译安装GDAL3.6.1(3.8.4)、链接Java(Java21)、加入FileGDB驱动

*** 2024-08-06,GDAL 3.9.1版本详细编译过程以及一键编译脚本,最新 博客地址

写在前面

​ 第一次Linux下编译源代码,遇到了很多坑,差点就放弃了,看了一下网上的教程都是老版本的,不是使用 CMake 方式的编

译,研究了很久总算弄出来了,希望能在思路上帮到大家,有问题可以留言,我会的帮解决

不会的只能再查了,如果我的搭建方式有问题,后续我会更新这篇博客的内容,

版本特别需求
Ubuntu 16.04 # 因为FileGDB驱动最高只支持Ubuntu16.04,更高的不支持了,如果你不用FileGDB驱动,更高版本也是可以的
jdk1.8
cmake 3.23.0 # 因为在Ubuntu16.04上直接apt安装的话它的版本GDAL编译不支持,所以得我们自己安装更高版本
gcc 5.x 
sqlite3 # 因为proj是依赖sqlite的,所以必须得安装
proj6 # 然后GDAL又是依赖proj的,所以proj又必须得安装,GDAL3.6.x以上3.7.x以下都得使用最低proj6
FileGDB 1.5.1-64gcc51 # 使用gcc版本最低不得低于5.x

# 其他需求在下面安装依赖的时候默认最新就行
1、更新源,创建目录

​ 可以直接复制粘贴然后运行,如果你想一条一条的运行就把 && 去掉。另外不太建议换成国内的源,可能会有
一些依赖找不到对应的版本,反正速度也不是特别慢,将就用吧。

apt update &&
mkdir /app &&
cd /app &&
mkdir java gdal filegdb proj cmake
2、复制各种包到容器免得下载
docker cp FileGDB_API_1_5_1-64gcc51.tar.gz ub:/app/filegd
docker cp jdk-8u202-linux-x64.tar.gz ub:/app/java
docker cp cmake-3.23.0.tar.gz ub:/app/cmake
docker cp gdal-3.6.1.tar.gz ub:/app/gdal
#docker cp 包 容器名:/app/对应的目录

​ 包的下载地址:


FileGDB,这是GitHub的地址,进去后自己找包,找到后直接点包,会进入具体的代码页面,
但是这是压缩包,看不到代码,右上角有个下载按钮直接下载就行,或者你找得到官网上的下载地址下载也行:
https://github.com/Esri/file-geodatabase-api/tree/master/FileGDB_API_1.5.1

jdk不提供,自己下,用的jdk1.8

cmake:
https://cmake.org/files/v3.23/cmake-3.23.0.tar.gz

gdal官方源代码包,可以去官方网站下载,也可以去GitHub上拉,我选择官网下:
https://github.com/OSGeo/gdal/releases/download/v3.6.1/gdal-3.6.1.tar.gz

3、安装各种依赖,有的用得上,有的用不上,难得分辨了
apt install -y build-essential wget vim unzip swig ant sqlite3 libsqlite3-dev \
pkg-config libopenjp2-7 libcairo2 libpng16-16 libjpeg-turbo8 libgif7 liblzma5 \
libgeos-c1v5 libxml2 libexpat1  libnetcdf-c++4 netcdf-bin libspatialite7 \
librasterlite2-1 gpsbabel libhdf4-0-alt poppler-utils \
libfreexl1 unixodbc mdbtools liblcms2-2 libpcre3 libcrypto++-dev libfyba0 \
libkmlbase1 libkmlconvenience1 libkmldom1 libkmlengine1 libkmlregionator1 \
libkmlxsd1  libzstd1 bash bash-completion libpq5 libblosc1 \
liblz4-1 libbrotli1 libarchive13 libssl-dev libgeos-3.5.0 libxerces-c3.1 libogdi3.2

#在下载的时候,如果有提示报错包没找到包不存在,就用 apt search xxx 来搜索xxx包,看下有没有其他版本的替代,用最新的就行
4、安装 Java
apt-get remove openjdk-* &&
cd /app/java/ &&
tar -zxvf jdk-8u202-linux-x64.tar.gz &&
mv jdk1.8.0_202/ jdk &&
rm jdk-8u202-linux-x64.tar.gz &&
vim ~/.bashrc

# 到这步没报错的话会进入一个文件,直接跳到最后,按A键编辑文件,添加下面这两个export到最后
export JAVA_HOME=/app/java/jdk
export PATH=$PATH:$JAVA_HOME/bin

# esc、 :(冒号) 、wq、回车保存
source ~/.bashrc &&
java -version

# 版本出现就正常,没出现或者报错就百度吧,这是Linux安装jdk,教程很多

5、安装 CMakeUbuntu16.04 的CMake版本GDAL编译不支持,我们自己找版本安装
# 先卸载系统上已经存在的CMake
apt remove cmake &&
apt autoremove &&
rm -rf /usr/bin/cmake* &&
rm -rf /usr/local/bin/cmake* &&
rm -rf /usr/share/cmake* &&
cd /app/cmake &&
# 解压
tar -zxvf cmake-3.23.0.tar.gz &&
cd cmake-3.23.0 &&
# 编译
./configure &&
make -j10 &&
# 安装
make install &&
cmake -version

# 出现版本正常:
# cmake version 3.23.0
# CMake suite maintained and supported by Kitware (kitware.com/cmake).
6、安装 PROJ6GDAL 的底层依赖 PROJ
cd /app/proj &&
# 下载包
wget http://download.osgeo.org/proj/proj-6.3.1.zip &&

# 包是zip格式的,要用unzip命令解压
unzip proj-6.3.1.zip &&
cd proj-6.3.1 &&

# 编译
./configure &&
make -j10 &&

#安装
make install &&
# 刷新配置
ldconfig &&

proj --version
# 出现版本正常:
# Rel. 6.3.1, February 10th, 2020
# <proj>: 
# invalid option: --
# program abnormally terminated
7、配置 FileGDB 驱动
cd /app/filegdb &&
tar -zxvf FileGDB_API_1_5_1-64gcc51.tar.gz &&
chown -R root:root FileGDB_API-64gcc51 &&
mv FileGDB_API-64gcc51 /usr/local/FileGDB_API &&
rm -rf /usr/local/FileGDB_API/lib/libstdc++* &&
cp /usr/local/FileGDB_API/lib/* /usr/lib/ &&
cp /usr/local/FileGDB_API/include/* /usr/include

# 这些命令建议直接复制,不要改任何东西,我一点一点试出来的,都是血和泪,
# 命令没问题,就是包所在的路径有问题,最好按照这个路径格式来,暂时不清楚是什么导致的
8、编译安装GDAL
# 到主要步骤了,请确定你的 swig、ant、proj、java安装正常并且版本正确
proj --version
ant -version
swig -version
java -version
echo $JAVA_HOME

cd /app/gdal &&
# 解压
tar -zxvf gdal-3.6.1.tar.gz &&
cd gdal-3.6.1 &&
# 创建一个build文件夹,这是官方建议的,别乱改
mkdir build &&
cd build &&

# DFileGDB_INCLUDE_DIR 意思是指定FileGDb驱动要用的头文件.h所在的文件夹,DFileGDB_LIBRARY 是FielGDB所需库文件所在的路径
cmake -DFileGDB_INCLUDE_DIR=/usr/local/FileGDB_API/include/ -DFileGDB_LIBRARY=/usr/lib/libFileGDBAPI.so -DCMAKE_BUILD_TYPE=Release ..
# DCMAKE_BUILD_TYPE=Release 默认写法,提升编译效率的
# 执行完成无误的输出应该是:
# -- Configuring done
# -- Generating done
# -- Build files have been written to: /app/gdal/gdal-3.6.1/build
# 并且没有任何报错


# 正式编译
cmake --build .
#中间有爆红不用管,只要结尾处100%的地方没有报错没有爆红就行

# 安装
cmake --build . --target install
# 没有报错就行

# 打开bash shell的配置文件
vim ~/.bashrc
# 如果你到现在是跟着我的目录来的话,加上这句话。如果你改了目录,那么就要对应修改路径
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib

# wq保存,source使配置生效
source ~/.bashrc

gdalinfo --version
# 如果打印出来的版本信息是这样那恭喜你完成了最凶险的一步:
# GDAL 3.6.1, released 2022/12/14

# 如果报错,请将/app/gdal/gdal-3.6.1/build 下的libgdal.*文件复制到/usr/local/lib下
cp /app/gdal/gdal-3.6.1/build/libgdal.* /usr/local/lib/
# 再试试 gdalinfo --version
9、配置GDALJava的链接(很坑)
# 进入swig文件夹
cd /app/gdal/gdal-3.6.1/build/swig/
# 如果有java文件夹,那么恭喜你,胜利就在眼前
# 我先说有java文件夹的怎么处理

# 有java文件夹则表示java的链接被编译成功,你进入java文件夹,应该能找到两个文件
cd java
ls
# CMakeFiles           build                javadoc.zip       tmp_test
# CTestTestfile.cmake  cmake_install.cmake  libgdalalljni.so
# Makefile             gdal.jar             org
# add_javadoc          java                 org_patched

# gdal.jar 和 libgdalalljni.so ,这两个是关键文件,jar文件是给你开发时候放到IDEA里面当maven依赖用的
# libgdalalljni.so 这个文件夹你要放到 /usr/local/lib 下,这个路径就是我们刚才配置环境变量LD_LIBRARY_PATH的那个路径
cp libgdalalljni.so /usr/local/lib


# 如果你的swig下没有java这个文件夹,那么请再次检查你的 ant和swig 有没有安装好
# 没有出现java文件夹,多半是ant或swig安装有问题,要么就是java环境有问题,因为gdal在编译的时候是自动的,
# 你环境齐全的话就会自动给你把java的链接编译出来,实在不行就重来吧
ant -version
swig -version

​ 到这步基本就算完了,写一个java测试

package org.example;

import org.gdal.gdal.gdal;
import org.gdal.ogr.*;

public class Main {
    public static void main(String[] args) {
        System.out.println("-------------------- start to load gdal .... --------------------");
        //获取数据源开始读文件
        gdal.AllRegister();
        // 为了支持中文路径,请添加下面这句代码
        gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
        //为了是属性表字段支持中文,请添加下面代码
        gdal.SetConfigOption("FILEGDB_ENCODING", "CP936");
        
        //获取驱动
        Driver driver = ogr.GetDriverByName("FileGDB");
        if (driver == null){
            System.out.println("-------------------- driver is null .... --------------------");
            return;
        }
        //获取数据源
        DataSource dataSource = driver.Open("/app/test.gdb");
        if (dataSource == null){
            System.out.println("-------------------- dataSource is null .... --------------------");
        }else {
            for (int i = 0; i < dataSource.GetLayerCount(); i++) {
                //获取图层
                Layer layer = dataSource.GetLayer(i);
                if (layer == null){
                    System.out.println("-------------------- layer is null,continue next layer --------------------");
                    continue;
                }
                for (long l = 0; l < layer.GetFeatureCount(); l++) {
                    //获取要素
                    Feature feature = layer.GetNextFeature();
                    if (feature == null){
                        System.out.println("-------------------- feature is null at fid :" + l + " --------------------");
                        continue;
                    }
                    //直接打印矢量数据
                    System.out.println(feature.GetGeometryRef().ExportToJson());
                }
            }
            System.out.println("==============  SUCCESS  ==============");
            System.out.println("==============  END  ==============");
        }
    }
}

​ 如果以上代码输出没有报错:

Native library load failed.
java.lang.UnsatisfiedLinkError: no gdalalljni in java.library.path
Exception in thread "main" java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:108)
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
        at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:65)
Caused by: java.lang.UnsatisfiedLinkError: org.gdal.gdal.gdalJNI.AllRegister()V
        at org.gdal.gdal.gdalJNI.AllRegister(Native Method)
        at org.gdal.gdal.gdal.AllRegister(gdal.java:684)
        at org.example.Main.main(Main.java:13)
        ... 8 more

​ 那就是成了,基本上能用了,我的也就到这步,还没进行过深度测试,有问题我会回来及时更改的

​ 顺便再提一句,如果编译GDAL要加上java的链接,那么 swigant 很重要,一定要确保这两个是没问题的

其他报错


1、这个报错主要体现在明明指定了FileGDB的路径并且库文件头文件都在,但就是读取不了导致GDAL一直编译不过,那么没错了就是这个错系统版本不支持,也就是你用了File GDB的驱动,但是你没用Ubuntu16.04,FileGDB不支持高版本的Ubuntu,最高支持16.04。这是GDAL的官方开发人员说的,不是我杜撰的。

CMake Error in CMakeLists.txt:
  IMPORTED_LOCATION not set for imported target "FILEGDB::FileGDB"
  configuration "Release".

​ 2、这个错可以参考第9步:

gdalinfo --version
gdalinfo: error while loading shared libraries: libgdal.so.32: cannot open shared object file: No such file or directory

我报错了一堆,暂时只记得这两个,想起来会继续补充。

------------------------------------------------------------------------ 分界线 ------------------------------------------------------------------------

2023-11-14更新:

今天把Dockerfile写出来了,需要的直接复制就行,注意将所需的文件都放在 ./dependency/下,当前目录就放Dockerfile文件

FROM ubuntu:16.04

LABEL maintainer="hyz <[email protected]>"

RUN apt update && mkdir /app && cd /app && mkdir java gdal filegdb proj cmake && \
apt install -y build-essential wget vim unzip swig ant sqlite3 libsqlite3-dev \
pkg-config libopenjp2-7 libcairo2 libpng16-16 libjpeg-turbo8 libgif7 liblzma5 \
libgeos-c1v5 libxml2 libexpat1  libnetcdf-c++4 netcdf-bin libspatialite7 \
librasterlite2-1 gpsbabel libhdf4-0-alt poppler-utils \
libfreexl1 unixodbc mdbtools liblcms2-2 libpcre3 libcrypto++-dev libfyba0 \
libkmlbase1 libkmlconvenience1 libkmldom1 libkmlengine1 libkmlregionator1 \
libkmlxsd1  libzstd1 bash bash-completion libpq5 libblosc1 \
liblz4-1 libbrotli1 libarchive13 libssl-dev libgeos-3.5.0 libxerces-c3.1 libogdi3.2


COPY ./dependency/FileGDB_API_1_5_1-64gcc51.tar.gz /app/filegdb
COPY ./dependency/jdk-8u202-linux-x64.tar.gz /app/java
COPY ./dependency/cmake-3.23.0.tar.gz /app/cmake
COPY ./dependency/gdal-3.6.1.tar.gz /app/gdal


RUN cd /app/java/ && tar -zxvf jdk-8u202-linux-x64.tar.gz && \
mv jdk1.8.0_202/ jdk && rm jdk-8u202-linux-x64.tar.gz
ENV JAVA_HOME=/app/java/jdk
ENV PATH=$PATH:$JAVA_HOME/bin


RUN apt remove cmake && apt autoremove && rm -rf /usr/bin/cmake* && rm -rf /usr/local/bin/cmake* && \
rm -rf /usr/share/cmake* && cd /app/cmake && tar -zxvf cmake-3.23.0.tar.gz && cd cmake-3.23.0 && \
./configure && make -j10 && make install


RUN cd /app/proj && wget http://download.osgeo.org/proj/proj-6.3.1.zip && unzip proj-6.3.1.zip && \
cd proj-6.3.1 && ./configure && make -j10 && make install && ldconfig


RUN cd /app/filegdb && tar -zxvf FileGDB_API_1_5_1-64gcc51.tar.gz && \
chown -R root:root FileGDB_API-64gcc51 && mv FileGDB_API-64gcc51 /usr/local/FileGDB_API && \
rm -rf /usr/local/FileGDB_API/lib/libstdc++* && cp /usr/local/FileGDB_API/lib/* /usr/lib/ && \
cp /usr/local/FileGDB_API/include/* /usr/include


RUN cd /app/gdal && tar -zxvf gdal-3.6.1.tar.gz && cd gdal-3.6.1 && mkdir build && cd build && \
cmake -DFileGDB_INCLUDE_DIR=/usr/local/FileGDB_API/include/ -DFileGDB_LIBRARY=/usr/lib/libFileGDBAPI.so -DCMAKE_BUILD_TYPE=Release .. \
&& cmake --build . && cmake --build . --target install 
ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib

RUN cd /app/gdal/gdal-3.6.1/build/swig/java && cp libgdalalljni.so /usr/local/lib

完事后直接 docker build 构建就行:

docker build -t gdal_java-env:1.0 .

注意后面的 . 别丢了

------------------------------------------------------------------- 分界线 2023-03-26 更新 --------------------------------------------------------------------

我又回来了,今天回来是对上面的博客有大更新,由于最近有GDB数据读取提速的需求,之前都是用Java8的多线程来读取GDB中的LayerFeature的,我也不知道怎么突然就盯上了Java21虚拟线程了,于是将环境更新,来跑新代码。
至于Java21读取GDB速率的提升,我也不晓得,没测试,但是我很有信心提速了,关于Java21,请看我另外一篇博客,讲Java21的虚拟线程的,链接放在这了

我也不磨叽了,直接放Dockerfile

FROM ubuntu:16.04

LABEL maintainer="hyz <[email protected]>"

RUN apt-get update && mkdir /app && cd /app && mkdir java gdal filegdb proj project cmake && \
apt-get install -y build-essential wget vim unzip swig ant sqlite3 libsqlite3-dev \
pkg-config libopenjp2-7 libcairo2 libpng16-16 libjpeg-turbo8 libgif7 liblzma5 \
libgeos-c1v5 libxml2 libexpat1  libnetcdf-c++4 netcdf-bin libspatialite7 \
librasterlite2-1 gpsbabel libhdf4-0-alt poppler-utils \
libfreexl1 unixodbc mdbtools liblcms2-2 libpcre3 libcrypto++-dev libfyba0 \
libkmlbase1 libkmlconvenience1 libkmldom1 libkmlengine1 libkmlregionator1 \
libkmlxsd1  libzstd1 bash bash-completion libpq5 libblosc1 \
liblz4-1 libbrotli1 libarchive13 libssl-dev libgeos-3.5.0 libxerces-c3.1 libogdi3.2


COPY ./dependency/FileGDB_API_1_5_1-64gcc51.tar.gz /app/filegdb
COPY ./dependency/jdk-21_linux-x64_bin.tar.gz /app/java
COPY ./dependency/cmake-3.23.0.tar.gz /app/cmake
COPY ./dependency/gdal-3.8.4.tar.gz /app/gdal


RUN cd /app/java/ && tar -zxvf jdk-21_linux-x64_bin.tar.gz && \
mv jdk-21.0.2/ jdk && rm jdk-21_linux-x64_bin.tar.gz
ENV JAVA_HOME=/app/java/jdk
ENV PATH=$PATH:$JAVA_HOME/bin


RUN apt-get remove cmake && apt autoremove && rm -rf /usr/bin/cmake* && rm -rf /usr/local/bin/cmake* && \
rm -rf /usr/share/cmake* && cd /app/cmake && tar -zxvf cmake-3.23.0.tar.gz && cd cmake-3.23.0 && \
./configure && make -j16 && make install


RUN cd /app/proj && wget http://download.osgeo.org/proj/proj-6.3.1.zip && unzip proj-6.3.1.zip && \
cd proj-6.3.1 && ./configure && make -j10 && make install && ldconfig


RUN cd /app/filegdb && tar -zxvf FileGDB_API_1_5_1-64gcc51.tar.gz && \
chown -R root:root FileGDB_API-64gcc51 && mv FileGDB_API-64gcc51 /usr/local/FileGDB_API && \
rm -rf /usr/local/FileGDB_API/lib/libstdc++* && cp /usr/local/FileGDB_API/lib/* /usr/lib/ && \
cp /usr/local/FileGDB_API/include/* /usr/include


RUN cd /app/gdal && tar -zxvf gdal-3.8.4.tar.gz && cd gdal-3.8.4 && mkdir build && cd swig/java && \
sed -i 's/debug="on" source="7" target="7"/debug="on" source="8" target="8"/g' build.xml && cd ../../build && \
cmake -DFileGDB_INCLUDE_DIR=/usr/local/FileGDB_API/include/ -DFileGDB_LIBRARY=/usr/lib/libFileGDBAPI.so \ 
-DCMAKE_BUILD_TYPE=Release .. && cmake --build . && cmake --build . --target install 
ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib

RUN cd /app/gdal/gdal-3.8.4/build/swig/java && cp libgdalalljni.so /usr/local/lib

记得去一开始我给的下载地址中,将所需的包下载下来放到 ./dependency ,也就是当前目录下的 dependency 文件夹中,或者你可以改Dockerfile中那几个 COPY 所指的那个地址。
变版本的包:jdk-21_linux-x64_bin.tar.gzgdal-3.8.4.tar.gz,没错,用了Java21了,gdal也用了3.8.4了,哦对了,还有个严重的问题,你可能会遇到,也可能遇不到,用我的Dockerfile的话应该遇不到,我提一嘴把。
如果在构建时遇到错误:

[ 93%] Generating gdal.jar, build/maven/gdal-3.8.4.jar, build/maven/gdal-3.8.4-sources.jar, 
		build/maven/gdal-3.8.4.pom, build/maven/gdal-3.8.4-javadoc.jar
Buildfile: /app/gdal/gdal-3.8.4/swig/java/build.xml

init:
     [echo] version = 3.8.4

compile:
    [mkdir] Created dir: /app/gdal/gdal-3.8.4/build/swig/java/build/classes
    [javac] Compiling 88 source files to /app/gdal/gdal-3.8.4/build/swig/java/build/classes
    [javac] warning: [options] bootstrap class path not set in conjunction with -source 7
    [javac] error: Source option 7 is no longer supported. Use 8 or later.
    [javac] error: Target option 7 is no longer supported. Use 8 or later.

那么没错,这是GDAL源码的问题,我去GitHub上查了,官方源码中 gdal/swig/java /build.xml 中有一段是这样的:

	<target name="compile" depends="init" description="Compile the source files.">
		<mkdir dir="${build_dir}/build/classes"/>
		<javac srcdir="${build_dir}/org" destdir="${build_dir}/build/classes"
		       debug="on" source="7" target="7"
		       includeantruntime="false" deprecation="true">
		</javac>
		<echo>compilation complete</echo>
	</target>

看到了嘛,它支持的最低版本是Java7,最新的GDAL3.8.4中已经改为了:

	<target name="compile" depends="init" description="Compile the source files.">
		<mkdir dir="${build_dir}/build/classes"/>
		<javac srcdir="${build_dir}/org" destdir="${build_dir}/build/classes"
		       debug="on" source="8" target="8"
		       includeantruntime="false" deprecation="true">
		</javac>
		<echo>compilation complete</echo>
	</target>

出现这个问题的原因是,你下载的GDAL3.8.4可能不是最新的 debug="on" source="8" target="8" ,我也不知道为啥会这样,可能是错乱了,我搞清楚再补充吧,总之在我的Dockerfile中解决了,倒数第二个RUN中:

RUN cd /app/gdal && tar -zxvf gdal-3.8.4.tar.gz && cd gdal-3.8.4 && mkdir build && cd swig/java && \
sed -i 's/debug="on" source="7" target="7"/debug="on" source="8" target="8"/g' build.xml

有一个 sed -i 's/debug="on" source="7" target="7"/debug="on" source="8" target="8"/g' build.xml ,这句的意思就是在修改导致错误的这个包中的这个不正确的代码,将debug="on" source="7" target="7" 改为 debug="on" source="8" target="8" ,总之这样改就没问题了,构建就能成功了。

docker build -t gdal_java-env:2.0 .

还是别忘了后面的那个 .

哎呀,我总是忘记事情,都发布了,又回来改:
* 还有一个问题,根据上面的流程构建好后,在容器内 /usr/bin中有一个 java文件,我也不知道哪一步多出来的,需要把这个文件删掉,不然你在这个镜像生成的容器内运行 java -version ,你会发现还是Java8,我们得删掉这个Java文件:

rm /usr/bin/java

再次运行 java -version 如果是Java21就没问题了

构建成功了,写一个Java21虚拟线程使用GDAL3.8.4读取Feature的测试代码:

public static void main(String[] args) throws ExecutionException, InterruptedException {
        long startTime = System.nanoTime();
        
        gdal.AllRegister();
        gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
        Driver driver = ogr.GetDriverByName("OpenFileGDB");
        DataSource dataSource = driver.Open("F:\\dev_file\\test_file\\test.gdb");
        
        System.out.println("开始表演...");
        
        final int slices = 6; //分片读取
        
        var futures = new ArrayList<Future<?>>();
        try (var exe = Executors.newVirtualThreadPerTaskExecutor()){
            for (int i = 0; i < dataSource.GetLayerCount(); i++) {
                var layer = dataSource.GetLayer(i);
                final long featureCount = layer.GetFeatureCount();
                final long sliceSize = featureCount / slices;
                for (int j = 0; j < slices; j++) {
                    int finalI = j;
                    futures.add(exe.submit(() -> {
                        var cpLayer = finalI == 0 ? 
                        			layer : driver.Open("F:\\dev_file\\test_file\\test.gdb").GetLayer(0);
                        long start = finalI * sliceSize;
                        long end = (finalI < slices - 1) ? start + sliceSize : featureCount;
                        cpLayer.SetNextByIndex(start);
                        for (long z = start; z < end; z++) {
                            Feature feature = cpLayer.GetNextFeature();
                            feature.GetGeometryRef().ExportToJson();
                            feature.delete();
                        }
                        
                    }));
                }
            }
        }
        
        for (Future<?> future : futures) {
            future.get();
        }
        dataSource.delete();
        long endTime = System.nanoTime();
        long duration = (endTime - startTime);  // 单位为纳秒
        System.out.println("耗时: " + duration / 1000000 + "毫秒");
    }

关于这个测试代码,后续我有时间会再详细的写一片新的博客解释的,这里面遇到的问题也很多。包括分片、单图层的线程问题、I/O密集CPU密集等问题,还有我试过很多的读取方法,包括生产者消费者模型。

忘了说了,我一开始原打算使用C++来实现上面的这个代码功能的,但是我不太熟C++,对于C++21中的协程更不熟了,
普通的C++多线程相对于Java的虚拟线程来说的话,提升并不是特别巨大,于是便又回到Java。
2023-03-26更新

后面想起其他的我会继续更新的。

;