shp文件在arcgis打开失败及其修复
shp文件在arcgis打开失败及其修复
ytkz引言
打开不了shp文件
同学们在平常使用arcgis的时候,是否遇到了下面这样的情况。
这是由于shp文件丢失了部分数据,导致在arcgis打不开。
1个 Shape文件结构Shape文件的文件构成Shape文件由3 个文件构成: 主文件、索引文件、数据文件。它们分别是“.shp” , “.shx””.dbf”文件。
如果数据文件dbf,丢失了部分数据,就会出现上面说的打不开的错误。
修复Shapefile的Python源代码
Shapefile实际上是一组几个相关文件的集合,其中最重要的是.shp(包含几何信息)、.dbf(包含属性信息)和.shx(包含索引信息)文件。有时,.shp文件和.dbf文件中的记录数量可能会不一致,这可能会导致GIS软件无法正确读取Shapefile。这个脚本的目的就是修复这种不一致。
代码详解
接下来,我将逐段解释这个脚本的代码:
- 导入所需的模块:脚本开始时,导入了需要的Python模块。这包括os、shutil(用于文件操作)、struct(用于处理二进制数据)和dbf(用于处理.dbf文件)。
- 定义RestoreShp类:这个类是脚本的核心,它包含了修复Shapefile的所有功能。
__init__
方法:这个方法是类的初始化方法。它接收两个参数:要修复的Shapefile的路径(file
)和输出文件的路径(outpath
)。如果outpath
没有提供,那么输出文件将被保存在file
所在的目录。如果file
不存在,那么会抛出一个异常。方法最后设置了self.outfile
,这是一个列表,包含了输出的.shp、.dbf和.shx文件的路径。copyfile
方法:这个方法将原始的Shapefile(.shp、.dbf和.shx文件)复制到输出目录。get_shp_shape_records
方法:这个方法读取.shp文件中的几何数据,并返回几何数据的数量。get_dbf_shape_records
方法:这个方法读取.dbf文件中的属性数据,并返回一个dbf.Table对象。restore_shp
方法:这个方法是修复Shapefile的主要方法。它首先获取.shp文件和.dbf文件中的记录数量,然后比较这两个数量。如果.shp文件的记录数量多,那么会在.dbf文件中添加记录;如果.dbf文件的记录数量多,那么会在.dbf文件中删除记录。
- 主程序:如果这个脚本被作为主程序运行(而不是被导入到其他脚本中),那么会执行这部分代码。它首先提示用户输入Shapefile的路径和输出文件的路径,然后创建一个
RestoreShp
对象,并调用其restore_shp
方法来修复Shapefile。如果修复成功,那么会输出“complete”;如果文件不存在,那么会输出“File does not exist”。
这就是这个脚本的全部内容。它提供了一种自动修复Shapefile记录数量不一致问题的方法
代码概述
脚本首先定义了一个名为RestoreShp
的类,这个类有三个主要的方法:
copyfile
:将原始的Shapefile(.shp、.dbf和.shx文件)复制到输出目录。get_shp_shape_records
:读取.shp文件中的几何数据,并返回几何数据的数量。get_dbf_shape_records
:读取.dbf文件中的属性数据,并返回属性数据的数量。
最后,restore_shp
方法使用上述方法,比较.shp文件和.dbf文件中的记录数量。如果数量不一致,它会相应地添加或删除记录,以使数量一致。
使用方法
要使用此脚本,首先需要在命令行中运行它,并按照提示输入Shapefile的路径和输出文件的路径。然后,脚本会自动修复Shapefile,并将修复后的文件保存到指定的输出路径。
注意事项
这个脚本使用了dbf
库来处理.dbf文件。在运行脚本之前,需要确保已经安装了这个库。可以使用以下命令进行安装:
pip install dbfread
完整代码
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2024/1/3 20:32
# @File : RestoreShp.py
# 修复shp文件, shp文件中的几何数据和属性数据不一致
import os
import shutil
from struct import unpack
import dbf
class RestoreShp(object):
def __init__(self, file, outpath=None):
self.file = file
self.outpath = outpath
if self.outpath is None:
self.outpath = os.path.dirname(self.file)
if not os.path.exists(self.outpath):
os.makedirs(self.outpath)
if os.path.exists(self.file) is None:
raise Exception('File does not exist')
else:
self.dbffile = os.path.splitext(self.file)[0] + '.dbf'
self.outfile = [os.path.join(self.outpath, os.path.splitext(os.path.basename(self.file))[0] + '_restore.shp'),
os.path.join(self.outpath, os.path.splitext(os.path.basename(self.file))[0] + '_restore.dbf'),
os.path.join(self.outpath, os.path.splitext(os.path.basename(self.file))[0] + '_restore.shx')]
self.copyfile
@property
def copyfile(self):
# 读取shp文件
shutil.copyfile(self.file, self.outfile[0])
shutil.copyfile(self.dbffile, self.outfile[1])
shutil.copyfile(os.path.splitext(self.file)[0] + '.shx', self.outfile[2])
print('Copy the initial file to the output directory')
def get_shp_shape_records(self):
try:
# First read the geometry data and attribute data of the original file, and return the number of geometric data
self.shx = open("%s" % (self.outfile[2]), "rb")
self.shx.seek(24)
shxRecordLength = (unpack(">i", self.shx.read(4))[0] * 2) - 100
self.numShapes = shxRecordLength // 8
return self.numShapes
except Exception as e:
print(e)
def get_dbf_shape_records(self):
# db = dbf.Dbf(self.dbffile)
with dbf.Table(self.outfile[1], codepage='utf8', default_data_types='enhanced') as table:
pass
return table
def restore_shp(self):
# Number of records read from shp file
shp_numrecords = self.get_shp_shape_records()
# Number of records read from dbf file
table = self.get_dbf_shape_records()
dbf_numrecords = len(table)
titles = dbf.get_fields(self.outfile[1])[0]
# Check whether the number of shp and dbf records is equal
if shp_numrecords != dbf_numrecords:
num = shp_numrecords - dbf_numrecords
if num > 0:
print('The shp file has {} more records than the dbf file'.format(num))
for i in range(num):
table.open(mode=dbf.READ_WRITE)
table.append()
table.pack()
else:
print('The dbf file has {} more records than the shp file'.format(abs(num)))
table.open(mode=dbf.READ_WRITE)
for record in table[shp_numrecords:]:
dbf.delete(record)
table.pack()
if __name__ == '__main__':
file = input('Please enter the path of the shp file: ')
outpath = input('Please enter the path of the output file: ')
if os.path.exists(file) :
record_num = RestoreShp(file, outpath).restore_shp()
print('complete')
else:
print('File does not exist')
input()
此外,这个脚本只处理了记录数量不一致的问题。如果Shapefile有其他类型的错误,例如几何数据或属性数据的格式错误,这个脚本可能无法修复。
开源代码地址在:
https://github.com/ytkz11/RestoreShp
如果对你有帮助,请点一个star!
快捷修复
我把以上的代码打包为一个命令行的exe,如果你对代码不熟练,可以直接运行这个exe,输入对应的文件路径,完成对shape文件的修复。
在公众号回复:shp修复
获得exe文件。