【ArcGIS Pro二次开发】(33):合并文件夹下的所有shp文件

在工作中经常会收到shp格式的文件,关于shp文件的吐糟就不多说了,除了文件小、字段名长度限制、不能储存弧线段等问题外,还有一种处理方式也让人很是难受。

【ArcGIS Pro二次开发】(33):合并文件夹下的所有shp文件_第1张图片

如上图,有些shp文件是分布在不同的文件夹里的,虽然方便了文件的分散传送,但没法像数据库一样统一管理,用起来很不方便。

这个工具的目的就是处理这一类型的文件,将分散的shp文件合并成一个数据库要素,并且保留文件名和相对路径,储存在2个新增字段里。


一、要实现的功能

【ArcGIS Pro二次开发】(33):合并文件夹下的所有shp文件_第2张图片

如上图所示,点击【合并 shp文件】按钮,输入【shp文件所在的文件夹】和【要保存的要素类的位置】(上图中路径显示不全,要保存为数据库的要素类),点击【执行】即可。

生成的结果如下:

【ArcGIS Pro二次开发】(33):合并文件夹下的所有shp文件_第3张图片

生成结果新增了2个字段,【SHP名称】是shp文件的文件名,【SHP路径】是shp文件的相对路径。

这样做是为了尽可能的保留shp文件的信息。尤其是【SHP路径】,可能包含了图斑所在的分区、类型等,将路径保留下来,方便后续处理。


二、实现流程

1、复制shp文件夹下的所有内容

由于后续需要对shp原文件进行添加字段、计算字段等操作,为了避免对原文件的改动和破坏,首先复制了shp文件夹下的所有内容,作为后续处理的数据。

        // 复制文件夹下的所有文件到新的位置
        public static void CopyAllFiles(string sourceDir, string destDir)
        {
            //目标目录不存在则创建
            if (!Directory.Exists(destDir))
            {
                Directory.CreateDirectory(destDir);
            }
            DirectoryInfo sourceDireInfo = new DirectoryInfo(sourceDir);
            List fileList = new List();
            GetFileList(sourceDireInfo, fileList); // 获取源文件夹下的所有文件
            List dirList = new List();
            GetDirList(sourceDireInfo, dirList); // 获取源文件夹下的所有子文件夹
            // 创建目标文件夹结构
            foreach (DirectoryInfo dir in dirList)
            {
                string sourcePath = dir.FullName;
                string destPath = sourcePath.Replace(sourceDir, destDir); // 替换源文件夹路径为目标文件夹路径
                if (!Directory.Exists(destPath))
                {
                    Directory.CreateDirectory(destPath); // 创建目标文件夹
                }
            }
            // 复制文件到目标文件夹
            foreach (FileInfo fileInfo in fileList)
            {
                string sourceFilePath = fileInfo.FullName;
                string destFilePath = sourceFilePath.Replace(sourceDir, destDir); // 替换源文件夹路径为目标文件夹路径
                File.Copy(sourceFilePath, destFilePath, true); // 复制文件,允许覆盖目标文件
            }
        }

        // 递归获取文件列表
        private static void GetFileList(DirectoryInfo dir, List fileList)
        {
            fileList.AddRange(dir.GetFiles()); // 添加当前文件夹下的所有文件
            foreach (DirectoryInfo directory in dir.GetDirectories())
            {
                GetFileList(directory, fileList); // 递归获取子文件夹下的文件
            }
        }

        // 递归获取子文件夹列表
        private static void GetDirList(DirectoryInfo dir, List dirList)
        {
            dirList.AddRange(dir.GetDirectories()); // 添加当前文件夹下的所有子文件夹

            foreach (DirectoryInfo directory in dir.GetDirectories())
            {
                GetDirList(directory, dirList); // 递归获取子文件夹下的子文件夹
            }
        }

这里采用了递归的方式获取文件列表和子文件夹列表。按原文件夹的目录创建了新的文件夹,并且把文件按原位置一个一个复制过去。

这部分代码我也没仔细研究,网上现成的代码很多,抄了一段直接用了。

2、获取文件夹下的所有shp文件

1个shp要素其实包含了很多文件,但我们只需要后缀名为shp的文件即可。

【ArcGIS Pro二次开发】(33):合并文件夹下的所有shp文件_第4张图片

按关键字获取特定文件的方法如下:

        // 获取输入文件夹下的所有文件
        public static List GetAllFiles(string folder_path, string key_word ="no match")
        {
            List filePaths = new List();

            // 获取当前文件夹下的所有文件
            string[] files = Directory.GetFiles(folder_path);
            // 判断是否包含关键字
            if (key_word == "no match")
            {
                filePaths.AddRange(files);
            }
            else
            {
                foreach (string file in files)
                {
                    // 检查文件名是否包含指定扩展名
                    if (Path.GetExtension(file).Equals(key_word, StringComparison.OrdinalIgnoreCase))
                    {
                        filePaths.Add(file);
                    }
                }
            }

方法引用:

// 获取所有shp文件
var files = ToolManager.GetAllFiles(shp_path, ".shp");

3、分别对单个shp文件单独新建标记字段,并赋值

                    // 获取路径标签
                    string tab = folder_path.Substring(folder_path.LastIndexOf(@"\") + 1);
                    // 分解文件夹目录,获取文件名和路径字段值
                    foreach (var file in files)
                    {
                        // 获取名称和路径
                        string short_path = file.Replace(def_path + @"\", "");
                        int index0 = short_path.IndexOf(@"\");            // 第一个【"\"】的位置
                        int index1 = short_path.LastIndexOf(@"\");      // 最后一个【"\"】的位置
                        int index2 = short_path.LastIndexOf(@".shp");  // 最后一个【".shp"】的位置
                        string name = short_path.Substring(index1 + 1, index2 - index1 - 1);
                        string path = tab + @"\" + short_path.Substring(index0 + 1, index1 - index0 - 1);
                        // 添加2个标记字段
                        Arcpy.AddField(file, @"SHP名称", "TEXT");
                        Arcpy.AddField(file, @"SHP路径", "TEXT");
                        Arcpy.CalculateField(file, @"SHP名称", "\"" + name + "\"");
                        Arcpy.CalculateField(file, @"SHP路径", "\"" + path + "\"");
                    }

这里主要是对字符串的切割,从绝对路径中获取要素名和相对路径。

不得不说,python在这方面比C#方便和灵活得多,有点怀念python。

获取所要的信息后,就可以将值赋给要素了。

PS:这里采用了GP工具来处理,其实挺不好,运行速度比较慢,如果碰上几百上千个要素,可能要等挺久。后面如果想到别的办法再来优化吧。(真的是边学边做,每过一个阶段回头看前面自己写的代码都像屎...)

最后将所有的shp要素合并即可:

// 合并要素
Arcpy.Merge(files, featureClass_path);

最后把复制出来的文件夹删掉:

// 删除复制的shp文件夹
Directory.Delete(shp_path, true);

以上就是工具的核心代码,完整代码请查看后面放出的工程文件。

需要注意的是为了不同工程的调用方便,一些通用方法我放到了几个类文件中。

【ArcGIS Pro二次开发】(33):合并文件夹下的所有shp文件_第5张图片


三、工程文件分享

 最后,放上工程文件的链接:

MergeSHPhttps://pan.baidu.com/s/1huEMRaDnxeVT3zHLonV6bw?pwd=2kgrPS:可以直接点击...bin\Debug\net6.0-windows\下的.esriAddinX文件直接安装。

你可能感兴趣的:(ArcGIS,ArcGIS,Pro,SDK,c#,二次开发,arcgis,pro,sdk,arcgis,pro,合并shp文件)