技术背景

  KML,是标记语言(Keyhole Markup Language)的缩写,最初由Keyhole公司开发,是一种基于XML 语法与格式的、用于描述和保存地理信息(如点、线、图像、多边形和模型等)的编码规范,可以被 Google Earth 和 Google Maps 识别并显示。

  创建这个工具只是因为一次偶然的需求,因为要将一个2G的点云数据导到Google Earth上进行显示,手动编辑绝对是不可能的,所以临时创建了这个小工具,为了方便使用,添加了一些简易的操作界面,这样便可以批量写入经纬度三维坐标数据(含高程)至kml文件内,然后导入Google Earth进行显示。关于kml文件的内部格式这里就不再详细描述了,具体内容请查看参考博客1【KML地图文件解析】。下面具体讲述一下程序设计原理。

实现原理

  本程序核心原理是很简单的,首先将.csv(或.txt)文件(内部格式为B,L,H 一行一个点坐标)读取以后,创建kml文件的头,然后根据kml文件的固定格式,将数据写入,最后文件写入完成以后,添加上文件的尾部格式。文件选择采用的是JFileChooser,具体使用方法请查看参考博客2【swing中JFileChooser的用法】。

  最后是界面的简要制作,添加两个控件,一个是用来选择文件的,另一个为程序退出按钮。不再具体阐述了,原理比较简单,直接上代码吧。

具体实现

  项目结构

  核心部分

  1. 1 package main;
  2. 2
  3. 3 import java.io.BufferedWriter;
  4. 4 import java.io.File;
  5. 5 import java.io.FileNotFoundException;
  6. 6 import java.io.FileOutputStream;
  7. 7 import java.io.FileReader;
  8. 8 import java.io.FileWriter;
  9. 9 import java.io.IOException;
  10. 10 import java.io.LineNumberReader;
  11. 11 import java.io.PrintStream;
  12. 12 import javax.swing.JFileChooser;
  13. 13 import javax.swing.JLabel;
  14. 14
  15. 15 public class BlhToKml {
  16. 16
  17. 17 /**
  18. 18 * @param args
  19. 19 */
  20. 20 public static String InputFilePath;
  21. 21 public static String OutputFilePath;
  22. 22 @SuppressWarnings("static-access")
  23. 23 public static void main() throws IOException{
  24. 24 JFileChooser jfc=new JFileChooser();
  25. 25 jfc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES );
  26. 26 jfc.showDialog(new JLabel(), "选择文件");
  27. 27 File file = jfc.getSelectedFile();
  28. 28 if(file == null){
  29. 29 return;
  30. 30 }
  31. 31 String FilePath = file.getAbsolutePath();
  32. 32 InputFilePath=FilePath;
  33. 33 OutputFilePath=InputFilePath;
  34. 34 if(OutputFilePath.indexOf(".")>=0)
  35. 35 {
  36. 36 OutputFilePath = OutputFilePath.substring(0, OutputFilePath.lastIndexOf("."));
  37. 37 }else{
  38. 38 return;
  39. 39 }
  40. 40 OutputFilePath=OutputFilePath+".kml";
  41. 41 //System.out.println(OutputFilePath);
  42. 42 WriteHeadInformationToFile1();
  43. 43 WriteHeadInformationToFile2();
  44. 44 ReplacePointInformation();
  45. 45 WriteEndInformationToFile();
  46. 46 TipFrame TF = new TipFrame();
  47. 47 TF.tishifu("已经转换完成!");
  48. 48 }
  49. 49 //将标题写入到指定路径下的文本内
  50. 50 public static void WriteHeadInformationToFile1() {
  51. 51 String filePath = OutputFilePath;
  52. 52 try {
  53. 53 File file = new File(filePath);
  54. 54 PrintStream ps = new PrintStream(new FileOutputStream(file));
  55. 55 ps.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
  56. 56 ps.append("<kml xmlns=\"http://www.opengis.net/kml/2.2\" xmlns:gx=\"http://www.google.com/kml/ext/2.2\" xmlns:kml=\"http://www.opengis.net/kml/2.2\"\r\n");
  57. 57 } catch (FileNotFoundException e){
  58. 58 e.printStackTrace();
  59. 59 }
  60. 60 }
  61. 61 public static void WriteHeadInformationToFile2(){
  62. 62 String filePath = OutputFilePath;
  63. 63 try {
  64. 64 FileWriter fw = new FileWriter(filePath, true);
  65. 65 BufferedWriter bw = new BufferedWriter(fw);
  66. 66 bw.write("xmlns:atom=\"http://www.w3.org/2005/Atom\">\r\n");
  67. 67 bw.write("<Document>\r\n");
  68. 68 bw.write("\t<name>Placemark.kml</name>\r\n");
  69. 69 bw.write("\t<Style id=\"sh_placemark_circle_highlight\">\r\n");
  70. 70 bw.write("\t\t<IconStyle>\r\n");
  71. 71 bw.write("\t\t\t<color>ff0000ff</color>\r\n");
  72. 72 bw.write("\t\t\t<scale>0.8</scale>\r\n");
  73. 73 bw.write("\t\t\t<Icon>\r\n");
  74. 74 bw.write("\t\t\t\t<href>http://maps.google.com/mapfiles/kml/shapes/open-diamond.png</href>\r\n");
  75. 75 bw.write("\t\t\t</Icon>\r\n");
  76. 76 bw.write("\t\t</IconStyle>\r\n");
  77. 77 bw.write("\t\t<ListStyle>\r\n");
  78. 78 bw.write("\t\t</ListStyle>\r\n");
  79. 79 bw.write("\t</Style>\r\n");
  80. 80 bw.write("\t<StyleMap id=\"msn_placemark_circle\">\r\n");
  81. 81 bw.write("\t\t<Pair>\r\n");
  82. 82 bw.write("\t\t\t<key>normal</key>\r\n");
  83. 83 bw.write("\t\t\t<styleUrl>#sn_placemark_circle</styleUrl>\r\n");
  84. 84 bw.write("\t\t</Pair>\r\n");
  85. 85 bw.write("\t\t<Pair>\r\n");
  86. 86 bw.write("\t\t\t<key>highlight</key>\r\n");
  87. 87 bw.write("\t\t\t<styleUrl>#sh_placemark_circle_highlight</styleUrl>\r\n");
  88. 88 bw.write("\t\t</Pair>\r\n");
  89. 89 bw.write("\t</StyleMap>\r\n");
  90. 90 bw.close();
  91. 91 fw.close();
  92. 92 } catch (Exception e) {
  93. 93 e.printStackTrace();
  94. 94 }
  95. 95 }
  96. 96 public static void ReplacePointInformation() throws IOException {
  97. 97 String filePath = OutputFilePath;
  98. 98 File sourceFile = new File(InputFilePath);
  99. 99 int lineNum = getTotalLines(sourceFile);
  100. 100 try {
  101. 101 FileWriter fw = new FileWriter(filePath, true);
  102. 102 BufferedWriter bw = new BufferedWriter(fw);
  103. 103 for(int i = 0;i<lineNum;i++){
  104. 104 bw.write("\t<Placemark>\r\n");
  105. 105 bw.write("\t\t<styleUrl>#msn_placemark_circle</styleUrl>\r\n");
  106. 106 bw.write("\t\t<Point>\r\n");
  107. 107 String str1=readAppointedLineNumber(sourceFile, i+1);
  108. 108 bw.write("\t\t\t<coordinates>"+str1+",</coordinates>\r\n");
  109. 109 bw.write("\t\t</Point>\r\n");
  110. 110 bw.write("\t</Placemark>\r\n");
  111. 111 }
  112. 112 bw.close();
  113. 113 fw.close();
  114. 114 } catch (Exception e) {
  115. 115 e.printStackTrace();
  116. 116 }
  117. 117 }
  118. 118 public static void WriteEndInformationToFile() {
  119. 119 String filePath = OutputFilePath;
  120. 120 try {
  121. 121 FileWriter fw = new FileWriter(filePath, true);
  122. 122 BufferedWriter bw = new BufferedWriter(fw);
  123. 123 bw.write("</Document>\r\n");
  124. 124 bw.write("</kml>");
  125. 125 bw.close();
  126. 126 fw.close();
  127. 127 } catch (Exception e) {
  128. 128 e.printStackTrace();
  129. 129 }
  130. 130 }
  131. 131 // 读取文件指定行。
  132. 132 public static String readAppointedLineNumber(File sourceFile, int lineNumber)
  133. 133 throws IOException {
  134. 134 FileReader in = new FileReader(sourceFile);
  135. 135 LineNumberReader reader = new LineNumberReader(in);
  136. 136 String s = "";
  137. 137 if (lineNumber <= 0 || lineNumber > getTotalLines(sourceFile)) {
  138. 138 System.out.println("不在文件的行数范围(1至总行数)之内。");
  139. 139 System.exit(0);
  140. 140 }
  141. 141 int lines = 0;
  142. 142 while (s != null) {
  143. 143 lines++;
  144. 144 s = reader.readLine();
  145. 145 if((lines - lineNumber) == 0) {
  146. 146 //System.out.println(s);
  147. 147 return s;
  148. 148 }
  149. 149 }
  150. 150 reader.close();
  151. 151 in.close();
  152. 152 return s;
  153. 153 }
  154. 154 // 文件内容的总行数。
  155. 155 public static int getTotalLines(File file) throws IOException {
  156. 156 FileReader in = new FileReader(file);
  157. 157 LineNumberReader reader = new LineNumberReader(in);
  158. 158 String s = reader.readLine();
  159. 159 int lines = 0;
  160. 160 while (s != null) {
  161. 161 lines++;
  162. 162 s = reader.readLine();
  163. 163 if(lines>=2){
  164. 164 if(s!=null){
  165. 165 //System.out.println(s+"$");
  166. 166 }
  167. 167 }
  168. 168 }
  169. 169 reader.close();
  170. 170 in.close();
  171. 171 //System.out.println(lines);
  172. 172 return lines;
  173. 173 }
  174. 174 }

  窗体部分1-主界面

  1. 1 package main;
  2. 2
  3. 3 import java.awt.Color;
  4. 4 import java.awt.FlowLayout;
  5. 5 import java.awt.Font;
  6. 6 import java.awt.Frame;
  7. 7 import java.awt.Label;
  8. 8 import java.awt.event.ActionEvent;
  9. 9 import java.awt.event.ActionListener;
  10. 10 import java.awt.event.WindowAdapter;
  11. 11 import java.awt.event.WindowEvent;
  12. 12 import java.io.IOException;
  13. 13 import javax.swing.JButton;
  14. 14 import javax.swing.JLabel;
  15. 15 import javax.swing.JPanel;
  16. 16
  17. 17 public class Frame1 {
  18. 18
  19. 19 /**
  20. 20 * @param args
  21. 21 */
  22. 22 public static void main(String[] args) {
  23. 23 // TODO Auto-generated method stub
  24. 24 major_Frame();
  25. 25 }
  26. 26 public static void major_Frame(){
  27. 27 final Frame major = new Frame("KML转换器");
  28. 28 major.setLayout(new FlowLayout(FlowLayout.CENTER));
  29. 29 major.setBounds(400, 300, 430, 250);
  30. 30 major.setBackground(new Color(255,255,255));
  31. 31 JPanel jPanel = new JPanel();//创建jPanel
  32. 32 jPanel.setBackground(new Color(255,255,255) );
  33. 33 jPanel.add(new JLabel("<html><br>\t每一行的数据属性为:精度,纬度,高程。每一个数据之间用英<br>" +
  34. 34 "文逗号隔开。<br><br><br></html>"));//为jPanel添加JLabel
  35. 35 Label label1 = new Label("格式提示");
  36. 36 label1.setFont(new Font("",1,18));//字体大小
  37. 37 label1.setBounds(100,200,400,200);
  38. 38 major.add(label1);
  39. 39 major.add(jPanel);
  40. 40 JButton btn1 = new JButton("输入");
  41. 41 btn1.addActionListener(new ActionListener(){
  42. 42 @SuppressWarnings("unused")
  43. 43 public void actionPerformed(ActionEvent arg0) {
  44. 44 // TODO Auto-generated method stub
  45. 45 BlhToKml blhtokml = new BlhToKml();
  46. 46 try {
  47. 47 BlhToKml.main();
  48. 48 } catch (IOException e) {
  49. 49 // TODO Auto-generated catch block
  50. 50 e.printStackTrace();
  51. 51 }
  52. 52 }
  53. 53
  54. 54 });
  55. 55 JButton btn2 = new JButton("退出");
  56. 56 btn2.addActionListener(new ActionListener(){
  57. 57 public void actionPerformed(ActionEvent e) {
  58. 58 major.setVisible(false);
  59. 59 System.exit(0);
  60. 60 }
  61. 61 });
  62. 62 major.add(btn1);
  63. 63 major.add(btn2);
  64. 64 major.addWindowListener(new WindowAdapter(){
  65. 65 public void windowClosing(WindowEvent e){
  66. 66 //System.exit(0);
  67. 67 major.setVisible(false);
  68. 68 major.dispose();
  69. 69 }
  70. 70 });
  71. 71 major.setVisible(true);
  72. 72 }
  73. 73
  74. 74 }

  窗体部分2-提示窗

  1. 1 package main;
  2. 2
  3. 3 import java.awt.FlowLayout;
  4. 4 import java.awt.Font;
  5. 5 import java.awt.Frame;
  6. 6 import java.awt.GridLayout;
  7. 7 import java.awt.Label;
  8. 8 import java.awt.event.MouseEvent;
  9. 9 import java.awt.event.MouseListener;
  10. 10 import java.awt.event.WindowAdapter;
  11. 11 import java.awt.event.WindowEvent;
  12. 12 import javax.swing.JButton;
  13. 13 import javax.swing.JPanel;
  14. 14
  15. 15 public class TipFrame {
  16. 16 public static void tishifu(String str){
  17. 17 final Frame f1=new Frame("提示");
  18. 18 f1.setBounds(500, 300, 300, 160);
  19. 19 f1.setResizable(false);
  20. 20 f1.setLayout(new GridLayout(2,1));
  21. 21 JPanel jpanel1 = new JPanel(new FlowLayout(FlowLayout.CENTER));
  22. 22 Label label1 = new Label(str);
  23. 23 label1.setFont(new Font("",1,15));
  24. 24 jpanel1.add(label1);
  25. 25 f1.add(jpanel1);
  26. 26 JPanel jpanel2 = new JPanel(new FlowLayout(FlowLayout.CENTER));
  27. 27 JButton Yes =new JButton("确定");
  28. 28 jpanel2.add(Yes);
  29. 29 f1.add(jpanel2);
  30. 30 f1.addWindowListener(new WindowAdapter() {
  31. 31 public void windowClosing(WindowEvent e) {
  32. 32 //System.exit(0);
  33. 33 f1.setVisible(false);
  34. 34 f1.dispose();
  35. 35 }
  36. 36 });
  37. 37 Yes.addMouseListener(new MouseListener(){
  38. 38 @Override
  39. 39 public void mouseClicked(MouseEvent arg0) {
  40. 40 // TODO 自动生成的方法存根
  41. 41 }
  42. 42 @Override
  43. 43 public void mouseEntered(MouseEvent arg0) {
  44. 44 // TODO 自动生成的方法存根
  45. 45 }
  46. 46 @Override
  47. 47 public void mouseExited(MouseEvent arg0) {
  48. 48 // TODO 自动生成的方法存根
  49. 49 }
  50. 50 public void mousePressed(MouseEvent arg0) {
  51. 51 // TODO 自动生成的方法存根
  52. 52 f1.setVisible(false);
  53. 53 f1.dispose();
  54. 54 }
  55. 55 @Override
  56. 56 public void mouseReleased(MouseEvent arg0) {
  57. 57 // TODO 自动生成的方法存根
  58. 58 }
  59. 59 });
  60. 60 f1.setVisible(true);
  61. 61 }
  62. 62 }

运行效果

  主窗体

  选择窗体

  提示窗

运行结果

  测试数据(部分)

  成果数据(部分)

  接下来导入到Google Earth就可以了

  至此,小工具设计完成了!

  源码我已经上传至博客园了,下载地址:https://files.cnblogs.com/files/thyou/BLH_to_KML.zip,希望能对使用kml文件这方面的同学有一丝帮助。

致谢

  感谢以下参考博客博主对于相关技术的分享交流,衷心感谢!

参考博客

1、KML地图文件解析【https://blog.csdn.net/onlymydreams_mfc/article/details/81840232】

2、swing中JFileChooser的用法【https://www.cnblogs.com/happyPawpaw/archive/2013/04/27/3046414.html】

经纬坐标(BLH)数据创建.kml文件小工具设计 Java版的更多相关文章

  1. 基于UDP传输协议局域网文件接收软件设计 Java版

    网路传输主要的两大协议为TCP/IP协议和UDP协议,本文主要介绍基于UDP传输的一个小软件分享,针对于Java网络初学者是一个很好的练笔,大家可以参考进行相关的联系,但愿能够帮助到大家. 话不多说, ...

  2. Swift - 从字典(或者Alamofire)直接创建Model文件的工具

    Swift - 从字典(或者Alamofire)直接创建Model文件的工具 效果 1. 常规生成model的方式 2. 通过debug创建model的方式 特性 1. 可以处理JSON格式的字典数据 ...

  3. WPF根据Oracle数据库的表,生成CS文件小工具

    开发小工具的原因: 1.我们公司的开发是客户端用C#,服务端用Java,前后台在通讯交互的时候,会用到Oracle数据库的字段,因为服务器端有公司总经理开发的一个根据Oracle数据库的表生成的cla ...

  4. WPF做的迁移文件小工具

    客户这边需要往服务器上传PDF文件.然后PDF文件很多,需要挑出来的PDF文件也不少.因此做了个小工具. 功能很简单,选定源文件夹,选定记录着要提取的文件的excel 文件.OK ,界面如下. XAM ...

  5. sqluldr2 oracle直接导出数据为文本的小工具使用

    近期客户有需求,导出某些审计数据,供审计人进行核查,只能导出成文本或excel格式的进行查看,这里我们使用sqluldr2工具进行相关数据的导出. oracle导出数据为文本格式比较麻烦,sqluld ...

  6. 【分享】生成Revit扩展的addin文件小工具

    在进行Revit二次开发的时候,加载命令/程序使用的是添加addin文件的方式,每次都需要手动的写,而且参数有好多,很不方便.于是乎我有了写一个小工具的想法.进过研究终于完成了.主要使用RevitAd ...

  7. 应用程序初次运行数据库配置小程序(Java版)

    应用程序初始化数据库配置小程序 之前写过一个Java版的信息管理系统,但部署系统的时候还需要手动的去配置数据库和导入一些初始化的数据才能让系统运行起来,所以我在想是不是可以写一个小程序在系统初次运行的 ...

  8. python实现文件搜索工具(简易版)

    在python学习过程中有一次需要进行GUI 的绘制, 而在python中有自带的库tkinter可以用来简单的GUI编写,于是转而学习tkinter库的使用. 学以致用,现在试着编写一个简单的磁文件 ...

  9. Duplicate Manager Pro for Mac(重复文件查找工具)破解版安装

    1.软件简介    Duplicate Manager Pro 是 macOS 系统上一款重复文件查找工具,可以帮你在 Mac 电脑上查找出磁盘上面的重复文件,然后让你对这些重复文件进行判断并删除,使 ...

随机推荐

  1. Apache Ant: If 和 Unless

    目录 If And Unless If And Unless 从 Ant 1.9.1 起,可以在所有的任务和嵌套的元素上以特别的命名空间添加 if 和 unless 属性. In order to u ...

  2. vulhub安装教程

    0x00 vulhub介绍 Vulhub是一个基于docker和docker-compose的漏洞环境集合,进入对应目录并执行一条语句即可启动一个全新的漏洞环境,让漏洞复现变得更加简单,让安全研究者更 ...

  3. Java打印空心三角

    Java打印空心三角 public static void main(String[] args) { int n=5; //n表示输出空心三角形行数,这里以5行为例 for(int i=1;i< ...

  4. 前端 | 自定义组件 v-model:Vue 如何实现双向绑定

    v-model 是 Vue 中一个常用的指令,常用于表单中的数据绑定.如下基本用法想必大家都很熟悉,data 中的 checked 属性的值就会随着多选框的状态实时变化. <el-checkbo ...

  5. 如何在Xamarin中快速集成Android版认证服务-手机号码篇

    Xamarin作为微软提供的移动服务多系统开发平台,成为很多开发者首选的应用开发平台.AppGallery Connect(以下简称AGC)也在逐步的支持Xamarin的SDK.认证服务也是支持Xam ...

  6. redis如何避免释放锁时把别人的锁释放掉

    场景:假如线程A获取分布式锁进入方法A,由于某种原因Hang住了 到了指定时间释放锁,这个时候线程B进入得到锁,这个时候线程B很顺利完成业务逻辑操作,然后释放掉锁,就在这个时候线程A开始继续往下执行代 ...

  7. golang中goroutine协程调度器设计策略

    goroutine与线程 /* goroutine与线程1. 可增长的栈os线程一般都有固定的栈内存,通常为2MB,一个goroutine的在其声明周期开始时只有很小的栈(2KB),goroutine ...

  8. 微服务架构 | 5.1 使用 Netflix Hystrix 断路器

    目录 前言 1. Hystrix 基础知识 1.1 Hystrix 断路器强调调用 1.2 两大类别的 Hystrix 实现 1.3 舱壁策略 1.4 Hystrix 在远程资源调用失败时的决策过程 ...

  9. python 小兵面向对象

    Python 面向对象 Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的.本章节我们将详细介绍Python的面向对象编程. 如果你以前没有接触过 ...

  10. jsp 4-14 知识总结

    二   string类型 装换 boolean 的方法? 三   attribute对象  set 和 get  的用法 四  jsp 的四种属性范围? 五  jsp  <%  %>  和 ...