golang实现shape属性编辑工具
2011 年 3 月 15 日
- 实现shape文件属性列表展示
- 导出shape属性类表为Excel
- 通过关联Excel表字段,新增shape字段
分析
github.com/jonas-p/go-shp@v0.1.1 github.com/tealeg/xlsx
工程目录结构
├─excel ├─html ├─shape ├─src │ └─main └─static
- excel目录:需要关联读取的excel
- html目录:前端html页面
- shape目录:需要操作的shape
- src目录:源文件
- static目录:静态文件
代码解读
读取shape
- 读取shape属性表头字段,主要代码如下:
func GetCols(shapefile string) []shp.Field { shape, err := shp.Open(shapefile) if err != nil { fmt.Errorf("UpdateShape err: %v", err) } defer shape.Close() fields := shape.Fields() return fields } 复制代码
- 读取shape属性表数据,主要代码如下:
shape, err := shp.Open(filepath) if err != nil { fmt.Errorf("UpdateShape err: %v", err) } defer shape.Close() fields := shape.Fields() results := make([]map[string]string, 0) for shape.Next() { n, p := shape.Shape() fmt.Println(n, p, fields, startPageNumber) if n >= (startPageNumber-1) && n = endPageNumber { break } } 复制代码
导出Excel
- shape数据保存为Excel文件,主要代码如下:
// 读取shape值 shape, err := shp.Open(ShapeFileName) if err != nil { fmt.Errorf("UpdateShape err: %v", err) } defer shape.Close() fields := shape.Fields() // 新建excel文件 file := xlsx.NewFile() sheet, _ := file.AddSheet("Sheet1") // add Header row := sheet.AddRow() row.SetHeightCM(1) //设置每行的高度 for k, f := range fields { cell := row.AddCell() cell.Value = f.String() fmt.Println(k) } for shape.Next() { row := sheet.AddRow() row.SetHeightCM(1) //设置每行的高度 n, p := shape.Shape() for k, f := range fields { val := shape.ReadAttribute(n, k) dec := mahonia.NewDecoder(Encoding) val = dec.ConvertString(val) fmt.Println(n, p, k, f, val) cell := row.AddCell() // 去除特殊字符 getVal := strings.Replace(val, " ", "", -1) getVal = strings.Replace(strconv.Quote(getVal), "\x00", "", -1) getVal = strings.Replace(getVal, "\"", "", -1) getVal = strings.Replace(getVal, "\\x00", "", -1) cell.Value = getVal } } //保存excel文件 errXlsx := file.Save("file.xlsx") 复制代码
-
下载Excel文件
后端golang主要代码:
func FileDownload(c *gin.Context, filename string) { c.Writer.Header().Add("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename)) //fmt.Sprintf("attachment; filename=%s", filename)对下载的文件重命名 c.Writer.Header().Add("Content-Type", "application/octet-stream") c.File(filename) } 复制代码
前端js代码
$("#exports").click(function () { if(shapename == ""){ layer.msg("请先选择文件") }else{ window.location.href = "/exports"; } }); 复制代码
字段关联
- 读取Excel文件表头字段
r.GET("/getExcelHead", func(context *gin.Context) { filename := context.Query("filename") fmt.Println("filename==" + filename) type Result struct { Code int `json:"code"` Msg string `json:"msg"` Data map[string]string `json:"data"` } var data = make(map[string]string) data = readExcelHead(filename) var result Result result.Code = 0 result.Msg = "success" result.Data = data context.JSON(http.StatusOK, result) }) 复制代码
-
读取shape属性表头字段:如上
GetCols
函数 -
Excel和shape字段关联

- shape新增字段和关联属性值Excel字段

新增shape字段
- 新增字段,主要代码如下:
addFields := []shp.Field{} dictValStr := "#" for bindKey, bindVal := range obj.AddList { fmt.Println(bindKey, bindVal, bindVal["newFiledText"], bindVal["bindFiledText"]) newFiledText := bindVal["newFiledText"] fmt.Println("newFiledText==" + newFiledText) addFields = append(addFields, shp.StringField(newFiledText, 64)) dictValStr = dictValStr + bindVal["bindFiledText"] + "#" } ... 复制代码
- 遍历shape属性,主要代码如下:
shp.UpdateShape(shapeFile, addFields, func(shape *shp.Reader, shapeNew *shp.Writer) { fieldsObj := shape.Fields() for shape.Next() { n, p := shape.Shape() shapeNew.Write(p) dictKeyStr = "#" for key, val := range obj.JoinObj { fmt.Println(key, val) shpVal := shape.GetValue(key) getVal := strings.Replace(shpVal, " ", "", -1) getVal = strings.Replace(strconv.Quote(getVal), "\x00", "", -1) getVal = strings.Replace(getVal, "\"", "", -1) getVal = strings.Replace(getVal, "\\x00", "", -1) dictKeyStr = dictKeyStr + getVal + "#" } for k, f := range fieldsObj { val := shape.ReadAttribute(n, k) dec := mahonia.NewDecoder(Encoding) val = dec.ConvertString(val) shapeNew.WriteAttribute(n, k, val) fmt.Println(k, f) } teampBindField := dictValStr[1 : len(dictValStr)-1] bindFileds := strings.Split(teampBindField, "#") for idx := 0; idx < len(bindFileds); idx++ { bindFiled := bindFileds[idx] newVal := DictData[dictKeyStr][bindFiled] shapeNew.WriteAttribute(n, len(fieldsObj)+idx, newVal) } } }) 复制代码
保存shape文件
- 上面函数
shp.UpdateShape
是在第三方go-shp 库扩展而来,主要实现生成新临时shape文件,并把这个临时shape文件替换原本的文件。主要代码如下:
func UpdateShape(src string, addFields []Field, callback func(shape *Reader, shapeNew *Writer)) { var dist string = time.Now().Format("teap_20060102150405") + ".shp" shape, err := Open(src) if err != nil { fmt.Errorf("UpdateShape err: %v", err) } defer shape.Close() // fields to write fields := shape.Fields() fields = append(fields, addFields...) //shapeNew, errNew := shp.Append("test.shp") shapeNew, errNew := Create(dist, POINT) if errNew != nil { fmt.Errorf("UpdateShape err: %v", errNew) } defer shapeNew.Close() shapeNew.SetFields(fields) //回调函数 callback(shape, shapeNew) shape.Close() shapeNew.Close() distarr := strings.Split(dist, ".") distName := distarr[0] srcarr := strings.Split(src, ".") srcName := srcarr[0] if len(srcarr) > 2 { // 说明路径中有多个. srcName = "." for i := 0; i < len(srcarr)-1; i++ { srcName = srcName + srcarr[i] } } shpSrc := srcName + ".shp" dbfSrc := srcName + ".dbf" shxSrc := srcName + ".shx" cpgSrc := srcName + ".cpg" shpDist := distName + ".shp" dbfDist := distName + ".dbf" shxDist := distName + ".shx" Copy(shpDist, shpSrc) Copy(dbfDist, dbfSrc) Copy(shxDist, shxSrc) // cpgFileWrite, err := os.Create(cpgSrc) cpgFileWrite.Write([]byte("UTF-8")) os.Remove(shpDist) os.Remove(dbfDist) os.Remove(shxDist) } 复制代码
文件拷贝
func Copy(src string, dist string) { //打开源文件 fileRead, err := os.Open(src) //fileRead, err := os.Open("C:/itcase/test-视频.avi") if err != nil { fmt.Println("Open err:", err) return } defer fileRead.Close() //创建目标文件 fileWrite, err := os.Create(dist) if err != nil { fmt.Println("Create err:", err) return } defer fileWrite.Close() //info, _ := os.Stat(src) //Stat获取文件属性 //filesize := info.Size() //从源文件获取数据,放到缓冲区 buf := make([]byte, 4096) //循环从源文件中获取数据,全部写到目标文件中 for { n, err := fileRead.Read(buf) if err != nil && err == io.EOF { //getProgress(src, filesize, n) fmt.Printf("读取完毕,n = d%\n:", n) return } fileWrite.Write(buf[:n]) //读多少、写多少 //getProgress(src, filesize, n) } } 复制代码
工具操作
main.exe

- 导出excel文件:点击
导出
能导出表格数据

- 关联新增:点击
关联新增
按钮,在弹出页面中,选择要的excel文件,关联shape和excel字段;添加新增字段和对应的绑定字段(即excel中的字段),最后点击保存
按钮。在执行完毕后,刷新页面读取shape列表,检查是否正确。
