利用线程池下载百度地图瓦片图详解编程语言

  继上一文章,百度地图离线功能,这里主要讲述下载瓦片图具体方法。

  1.利用全能电子地图下载带水印的瓦片图。其中文件夹路径为tile/层级/x/y.jpg,如下图所示,全能电子地图1.9下载的百度地图瓦片图是一个个黑点。

利用线程池下载百度地图瓦片图详解编程语言

  2.根据图片url下载图片,根据URL获取HttpURLConnection, 根据HttpURLConnection获取输入流InputStream ,在用输出流OutputStream out = new FileOutputStream(file);将字节写入文件即可。此方法为单线程下载,代码如下:

/** 
 * 下载图片 
 */ 
public class BaiDuMapDownload { 
    static volatile Integer c = 0;//成功数 
    static volatile Integer fail = 0;//失败数量
public static void main(String[] args) throws Exception { String link = "http://online3.map.bdimg.com/onlinelabel/?qt=tile&x={x}&y={y}&z={z}&styles=pl&udt=20170712&scaler=1&p=1"; int z = 19;//层级 int xmin = 103514;//x最小值 int xmax = 104292;//x最大值 int ymin = 29400;//y最小值 int ymax = 30700;//y最大值 for (int i = xmin; i <= xmax; i++) { //循环X for (int j = ymin; j <= ymax; j++) { //循环Y try {
URL url
= new URL(link.replace("{x}", i + "").replace("{y}", j + "").replace("{z}", z + "")); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(100); conn.connect(); InputStream in = conn.getInputStream(); File dir = new File("d:/mybaidumapdownload1/tiles/" + z + "/" + i); if (!dir.exists()) { dir.mkdirs(); } File file = new File("d:/mybaidumapdownload1/tiles/" + z + "/" + i + "/" + j + ".jpg"); if (!file.exists()) { file.createNewFile(); } OutputStream out = new FileOutputStream(file); byte[] bytes = new byte[1024 * 20]; int len = 0; while ((len = in.read(bytes)) != -1) { out.write(bytes, 0, len); } out.close(); in.close(); //System.out.println("已成功下载:" + z + "_" + i + "_" + j + ".jpg"); c++; } catch (Exception e) { System.out.println(e.getMessage()); fail++; }
}
//循环Y结束 } //循环X结束 Thread.sleep(1000); System.out.println("共下载: " + c + " 张"); System.out.println("失败: " + fail + " 张"); } }

  3.通过上面的代码就可以下载百度图片,但是很明显,上面代码是单线程,而且会IO阻塞,百度地图下载到第19级时有将近一百万的瓦片图。

线程池ThreadPoolExecutor优化下代码。本来两天才能下完的图时间缩减一天会感觉很棒。

/** 
 * 线程池下载图片 
 */ 
class BDTask implements Runnable{ 
    String link; 
    int i;  //x坐标 
    int j;  //y坐标 
    int z;  //缩放级别 
 
    static volatile Integer c = 0;//成功数 
    static volatile Integer fail = 0;//失败数量 
 
    public BDTask(String link, int i, int j, int z) { 
        this.link = link; 
        this.i = i; 
        this.j = j; 
        this.z = z; 
 
    } 
    public static void main(String[] args) 
            throws Exception { 
        String link = "http://online3.map.bdimg.com/onlinelabel/?qt=tile&x={x}&y={y}&z={z}&styles=pl&udt=20170712&scaler=1&p=1"; 
        int z = 12;  //层级 
        int xmin = 808; //x最小值 
        int xmax = 814;  //x最大值 
        int ymin = 230;  //y最小值 
        int ymax = 239;  //y最大值 
        //创建线程池,corePoolSize两条线程,最大存在四条线程,大于corePoolSize小于MaxmumPoolSize的线程等待空闲时间为500毫秒,任务队列LinkBlockingQueue不写时的默认值为Integer默认值. 
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2,4,500, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); 
        for (int i = xmin; i <= xmax; i++) {   //循环X 
            for (int j = ymin; j <= ymax; j++) {    //循环Y 
                threadPoolExecutor.execute(new BDTask(link,i,j,z)); 
                //new Thread(new BDTask(link,i,j,z)).start();    //此种方法会一直创建线程导致死机 
            }    //循环Y结束 
        }   //循环X结束 
        threadPoolExecutor.shutdown();   //关闭线程池 
        while (!threadPoolExecutor.isTerminated()){}     //一直循环等到所有任务被执行完毕时继续往下执行 
        System.out.println("共下载:   " + c + "   张"); 
        System.out.println("失败:   " + fail + "   张"); 
    } 
 
    public void run() { 
        try { 
            URL url = new URL(link.replace("{x}", i + "").replace("{y}", j + "").replace("{z}", z + "")); 
            HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 
            conn.setConnectTimeout(100); 
            conn.connect(); 
            InputStream in = conn.getInputStream(); 
            File dir = new File("d:/mybaidumapdownload1/tiles/" + z + "/" + i); 
            if (!dir.exists()) { 
                dir.mkdirs(); 
            } 
            File file = new File("d:/mybaidumapdownload1/tiles/" + z + "/" + i + "/" + j + ".jpg"); 
            if (!file.exists()) { 
                file.createNewFile(); 
            } 
            OutputStream out = new FileOutputStream(file); 
            byte[] bytes = new byte[1024 * 20]; 
            int len = 0; 
            while ((len = in.read(bytes)) != -1) { 
                out.write(bytes, 0, len); 
            } 
            out.close(); 
            in.close(); 
            synchronized (fail) { 
                c++; 
            } 
        } catch (Exception e) { 
            System.out.println(e.getMessage()); 
            synchronized (c) { 
                fail++; 
            } 
        } 
    } 
}

包装一下方便使用

利用线程池下载百度地图瓦片图详解编程语言

  其中,baiduMap.properties的link为下载地址,rootDir为存储地址

  BaiDuMapDownloadByThreadPool.java代码如下

 

package com.autumn.dao; 
 
import java.io.File; 
import java.io.*; 
import java.net.HttpURLConnection; 
import java.net.URL; 
import java.util.Properties; 
import java.util.concurrent.LinkedBlockingQueue; 
import java.util.concurrent.ThreadPoolExecutor; 
import java.util.concurrent.TimeUnit; 
 
/** 
 * 下载图片 
 */ 
public class BaiDuMapDownloadByThreadPool { 
    public static void main(String[] args) 
            throws Exception { 
 
        //根据properties文件配置url和存储路径 
        Properties properties = new Properties(); 
        File file = new File("classpath:baiduMap.properties"); 
        InputStream inputStream = BaiDuMapDownloadByThreadPool.class.getResourceAsStream("baiduMap.properties"); 
        //判断是否有此文件 
        if (inputStream!=null) { 
            properties.load(inputStream); 
            String link = properties.getProperty("link"); 
            if (link!=null&&!link.isEmpty()){ 
                BDTask.link=link; 
            } 
            String rootDir = properties.getProperty("rootDir"); 
            if (rootDir!=null&&!rootDir.isEmpty()){ 
                BDTask.rootDir=rootDir; 
            } 
        } 
 
        BDTask.startDownload(); 
    } 
} 
 
/** 
 * 线程池下载图片 
 */ 
class BDTask implements Runnable { 
    //正常百度地图String link = "http://online3.map.bdimg.com/onlinelabel/?qt=tile&x={x}&y={y}&z={z}&styles=pl&udt=20170712&scaler=1&p=1"; 
    //午夜蓝版 
    static String link ="http://api0.map.bdimg.com/customimage/tile?&x={x}&y={y}&z={z}&udt=20180711&scale=1&ak=0F7691e465f5d7d161a4771f48ee38ff&styles=t%3Awater%7Ce%3Aall%7Cc%3A%23021019%2Ct%3Ahighway%7Ce%3Ag.f%7Cc%3A%23000000%2Ct%3Ahighway%7Ce%3Ag.s%7Cc%3A%23147a92%2Ct%3Aarterial%7Ce%3Ag.f%7Cc%3A%23000000%2Ct%3Aarterial%7Ce%3Ag.s%7Cc%3A%230b3d51%2Ct%3Alocal%7Ce%3Ag%7Cc%3A%23000000%2Ct%3Aland%7Ce%3Aall%7Cc%3A%2308304b%2Ct%3Arailway%7Ce%3Ag.f%7Cc%3A%23000000%2Ct%3Arailway%7Ce%3Ag.s%7Cc%3A%2308304b%2Ct%3Asubway%7Ce%3Ag%7Cl%3A-70%2Ct%3Abuilding%7Ce%3Ag.f%7Cc%3A%23000000%2Ct%3Aall%7Ce%3Al.t.f%7Cc%3A%23857f7f%2Ct%3Aall%7Ce%3Al.t.s%7Cc%3A%23000000%2Ct%3Abuilding%7Ce%3Ag%7Cc%3A%23022338%2Ct%3Agreen%7Ce%3Ag%7Cc%3A%23062032%2Ct%3Aboundary%7Ce%3Aall%7Cc%3A%231e1c1c%2Ct%3Amanmade%7Ce%3Ag%7Cc%3A%23022338%2Ct%3Apoi%7Ce%3Aall%7Cv%3Aoff%2Ct%3Aall%7Ce%3Al.i%7Cv%3Aoff%2Ct%3Aall%7Ce%3Al.t.f%7Cv%3Aon%7Cc%3A%232da0c6";; 
    static String rootDir = "d:/mybaidumapdownload1"; 
 
    int i;  //x坐标 
    int j;  //y坐标 
    int z;  //缩放级别 
 
    static volatile Integer c = 0;//成功数 
    static volatile Integer fail = 0;//失败数量 
 
    public BDTask(String link, int i, int j, int z) { 
        this.link = link; 
        this.i = i; 
        this.j = j; 
        this.z = z; 
 
    } 
 
    public static void startDownload() { 
        ThreadPoolExecutor threadPoolExecutor = null; 
        long start = 0L; 
        for(Level c : Level.values()){ 
            int z = c.getLevel(); 
            int xmin = c.getX_min(); 
            int xmax = c.getX_max(); 
            int ymin = c.getY_min(); 
            int ymax = c.getY_max(); 
            start = System.currentTimeMillis();    //开始时间 
            threadPoolExecutor = new ThreadPoolExecutor(2, 4, 500, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); 
            for (int i = xmin; i <= xmax; i++) {   //循环X 
                for (int j = ymin; j <= ymax; j++) {    //循环Y 
                    threadPoolExecutor.execute(new BDTask(link, i, j, z));  //下载图片 
                    //new Thread(new BDTask(link,i,j,z)).start();    //此种方法会一直创建线程导致死机 
                        /*try { 
                            URL url = new URL(link.replace("{x}", i + "").replace("{y}", j + "").replace("{z}", z + "")); 
                            HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 
                            conn.setConnectTimeout(100); 
                            conn.connect(); 
                            InputStream in = conn.getInputStream(); 
                            File dir = new File("d:/mybaidumapdownload1/tiles/" + z + "/" + i); 
                            if (!dir.exists()) { 
                                dir.mkdirs(); 
                            } 
                            File file = new File("d:/mybaidumapdownload1/tiles/" + z + "/" + i + "/" + j + ".jpg"); 
                            if (!file.exists()) { 
                                file.createNewFile(); 
                            } 
                            OutputStream out = new FileOutputStream(file); 
                            byte[] bytes = new byte[1024 * 20]; 
                            int len = 0; 
                            while ((len = in.read(bytes)) != -1) { 
                                out.write(bytes, 0, len); 
                            } 
                            out.close(); 
                            in.close(); 
                            //System.out.println("已成功下载:" + z + "_" + i + "_" + j + ".jpg"); 
                            c++; 
                        } catch (Exception e) { 
                            System.out.println(e.getMessage()); 
                            fail++; 
                        }*/ 
                }    //循环Y结束 
            }   //循环X结束 
        } 
 
        threadPoolExecutor.shutdown();   //关闭线程池 
        while (!threadPoolExecutor.isTerminated()) { 
        }     //所有任务被执行完毕时继续往下执行 
        System.out.println("-------用时-------:" + (System.currentTimeMillis() - start)); 
        System.out.println("共下载:   " + c + "   张"); 
        System.out.println("失败:   " + fail + "   张"); 
    } 
 
    public void run() { 
        try { 
            URL url = new URL(link.replace("{x}", i + "").replace("{y}", j + "").replace("{z}", z + "")); 
            HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 
            conn.setConnectTimeout(100); 
            conn.connect(); 
            InputStream in = conn.getInputStream(); 
 
            File file = new File(rootDir+"/tiles/" + z + "/" + i + "/" + j + ".jpg"); 
            if (!file.getParentFile().exists()) { 
                file.getParentFile().mkdirs(); 
            } 
            file.createNewFile(); 
 
            OutputStream out = new FileOutputStream(file); 
            byte[] bytes = new byte[1024 * 20]; 
            int len = 0; 
            while ((len = in.read(bytes)) != -1) { 
                out.write(bytes, 0, len); 
            } 
            out.close(); 
            in.close(); 
            synchronized (fail) { 
                c++; 
            } 
        } catch (Exception e) { 
            System.out.println(e.getMessage()); 
            synchronized (c) { 
                fail++; 
            } 
        } 
    } 
} 
 
/** 
 * 枚举类型,这里所有的等级和xy轴数据为扬州的地图 
 * 等级 x最小 x最大 y最小 y最大 
 */ 
enum Level { 
    Level_3(3, 1, 1, 0, 0), 
    Level_4(4, 3, 3, 0, 0), 
    Level_5(5, 6, 6, 1, 3), 
    Level_6(6, 12, 12, 3, 3), 
    Level_7(7, 25, 25, 7, 7), 
    Level_8(8, 50, 50, 14, 14), 
    Level_9(9, 101, 101, 28, 29), 
    Level_10(10, 202, 203, 57, 59), 
    Level_11(11, 404, 407, 115, 119), 
    Level_12(12, 808, 814, 230,239), 
    Level_13(13, 1617, 1629, 460, 480), 
    Level_14(14, 3234, 3259, 920, 960), 
    Level_15(15, 6469, 6518, 1840, 1920), 
    Level_16(16, 12939, 13036, 3680, 3850), 
    Level_17(17, 25878, 26073, 7360, 7670), 
    Level_18(18, 51757, 52146, 14720,15400), 
    Level_19(19, 103514, 104292, 29400,30700); 
 
    private int level; 
    private int x_min; 
    private int x_max; 
    private int y_min; 
    private int y_max; 
 
    Level(int level, int x_min, int x_max, int y_min, int y_max) { 
        this.level = level; 
        this.x_min = x_min; 
        this.x_max = x_max; 
        this.y_min = y_min; 
        this.y_max = y_max; 
    } 
 
    public int getLevel() { 
        return level; 
    } 
 
    public int getX_min() { 
        return x_min; 
    } 
 
    public int getX_max() { 
        return x_max; 
    } 
 
    public int getY_min() { 
        return y_min; 
    } 
 
    public int getY_max() { 
        return y_max; 
    } 
}

源码

原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/17821.html

(0)
上一篇 2021年7月19日 20:33
下一篇 2021年7月19日 20:33

相关推荐

发表回复

登录后才能评论