>>> from env_helper import info; info()
页面更新时间: 2024-01-13 09:32:14
运行环境:
    Linux发行版本: Debian GNU/Linux 12 (bookworm)
    操作系统内核: Linux-6.1.0-16-amd64-x86_64-with-glibc2.36
    Python版本: 3.11.2

5.3. 写入矢量数据

一个矢量文件可以通过模式 'a' (append) 打开,也可以通过模式 'w' (write)写入。 注意:OGR“update” 模式没有独立格式,因此,Fiona不支持。

5.3.1. 添加数据到现有文件

>>> import fiona
>>> with fiona.open('/gdata/prov_capital.shp') as c:
>>>     rec = next(iter(c))
>>> rec['id'] = '-1'
>>> rec['properties']['CNTRY_NAME'] = 'Gondor'
/tmp/ipykernel_180500/4290745662.py:4: FionaDeprecationWarning: instances of this class -- CRS, geometry, and feature objects -- will become immutable in fiona version 2.0
  rec['id'] = '-1'
/tmp/ipykernel_180500/4290745662.py:5: FionaDeprecationWarning: instances of this class -- CRS, geometry, and feature objects -- will become immutable in fiona version 2.0
  rec['properties']['CNTRY_NAME'] = 'Gondor'

注意上面的用法,在 Fiona 2.0 后,不可以用这种方法修改对象。

>>> from fiona import os
>>> os.system("cp /gdata/prov_capital.* /tmp")
0

注意,在文件修改前要拷贝备份。

这样,坐标参考系统、 .format 与文件架构就定义完成,所以他不能以只读方式打开,也不能是 'a' 模式。 新的记录用 fiona.collection.Collection.write 的方式写在文件最尾处,因此,该文件的长度就从 48 增加到了 49

>>> import os, stat
>>> shp_file = '/tmp/prov_capital'
>>> os.chmod(shp_file + '.shp', stat.S_IRUSR + stat.S_IWUSR)
>>> os.chmod(shp_file + '.dbf', stat.S_IRUSR + stat.S_IWUSR)
>>> os.chmod(shp_file + '.shx', stat.S_IRUSR + stat.S_IWUSR)
>>> with fiona.open(shp_file + '.shp', 'a') as c:
>>>     print(len(c))
34

你写入的记录必须匹配文件模式(因为一个文件包含一个记录型)。如果不是的话,会出现 ValueError 的异常。

with fiona.open(shp_file + '.shp', 'a') as c:
    c.write({'properties': {'foo': 'bar'}})
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)

若忽略一个记录的ID值,可能就会被下一个生成的值替换掉。如果你只是读文件,仅参考上面的即可,

>>> shp_file = '/tmp/prov_capital'
>>> os.chmod(shp_file + '.shp', stat.S_IRUSR + stat.S_IWUSR)
>>> os.chmod(shp_file + '.dbf', stat.S_IRUSR + stat.S_IWUSR)
>>> os.chmod(shp_file + '.shx', stat.S_IRUSR + stat.S_IWUSR)
>>> with fiona.open('/tmp/prov_capital.shp') as c:
>>>     records = list(c)   # records = c.next()
>>> records[-1]['id']
'33'
>>> records[-1]['properties']['name']
'澳门'

你可能还会看到ID值为 '-1' ,这记录有时可能会被 '48' 替换掉。

fiona.collection.Collection. 是文件集的唯一记录。 fiona.collection.Collection.writerecords 的写入会成为序列值(或迭代器)。

>>> with fiona.open('/tmp/prov_capital.shp', 'a') as c:
>>>     c.writerecords([rec, rec,rec])
>>>     print(len(c))
---------------------------------------------------------------------------

ValueError                                Traceback (most recent call last)

Cell In [8], line 2
      1 with fiona.open('/tmp/prov_capital.shp', 'a') as c:
----> 2     c.writerecords([rec, rec,rec])
      3     print(len(c))


File /usr/lib/python3/dist-packages/fiona/collection.py:551, in Collection.writerecords(self, records)
    549 if self.mode not in ("a", "w"):
    550     raise OSError("collection not open for writing")
--> 551 self.session.writerecs(records, self)
    552 self._len = self.session.get_length()
    553 self._bounds = None


File fiona/ogrext.pyx:1344, in fiona.ogrext.WritingSession.writerecs()


ValueError: Record does not match collection schema: KeysView(<fiona.model.Properties object at 0x7f2ad574b550>) != ['lat', 'lon', 'name']
  • 复制。Fiona集有复制功能。以上的代码共复制了3次,而且它们都有独立的ID号。

  • 缓冲。Fiona输出有缓冲功能。在集关闭后,writewriterecords 在磁盘内会刷新。你也可以叫作 flush,会定期写进磁盘的缓冲区域。

5.3.2. 写入新文件

写一个新文件比添加现有文件要复杂,因为 CRS、格式、模式等都尚未创建,而且这些都是必做的。 解决方法就是上面所述的映射模式。 CRS有映射功能, fiona.drivers 列表基本把可能的CRS映射格式都已列举出来。

>>> with fiona.open('/gdata/prov_capital.shp') as source:
>>>     source_driver = source.driver
>>>     source_crs = source.crs
>>>     source_schema = source.schema
>>> print(source_driver)
ESRI Shapefile
>>>
>>> source_crs
CRS.from_epsg(4326)
>>> from pprint import pprint
>>> pprint(source_schema)
{'geometry': 'Point',
 'properties': OrderedDict([('name', 'str:100'),
                            ('lat', 'float:13.11'),
                            ('lon', 'float:13.11')])}

现在创建一个新文件。

>>> c = fiona.open( '/tmp/foo.shp', 'w', driver=source_driver, crs=source_crs, schema=source_schema)
>>> len(c)
0
>>> c.closed
False
>>> len(c)
0

由于对源架构的性能有要求,可以在写入的模式集中使用同一命令,书面文件的字段可与源文件使用同一命令。

ogrinfo '/tmp/foo.shp' foo -so
INFO: Open of `/tmp/foo.shp'
using driver `ESRI Shapefile' successful.

~fiona.collection.Collection.meta 属性可以使复制文件元属性更加容易。

>>> source = fiona.open('/gdata/prov_capital.shp')
>>> sink = fiona.open('/tmp/foo.shp', 'w', **source.meta)

5.3.3. 排序字段(Ordering Record Fields)

在Fiona 1.0.1中, fiona.openschema 参数就是一个有序的库列表(键,值),并指定一个序列。 如果给定一个常规库,用输出 ~items 库的方法来排序。例如,

>>> {'bar': 'int', 'foo': 'str'}.keys()
dict_keys(['bar', 'foo'])

{'properties': {'bar': 'int', 'foo': 'str'}} 模式可生成 Shapefile ,第一个字段是 foo ,第二个字段是 bar 。 如果你想要把 bar 作为第一个字段,你必须用一个属性列表项。

另外,要注意在 schema 要声明 geometry ,其类型为 Polygon ,注意大小写。

>>> c = fiona.open( '/tmp/foo2.shp', 'w',schema={'properties': [('bar', 'int'), ('foo', 'str')], 'geometry': 'Polygon'}, driver = 'ESRI Shapefile')

或者使用 OrderedDict

>>> from collections import OrderedDict
>>> schema_props = OrderedDict([('bar', 'int'), ('foo', 'str')])
>>> c = fiona.open('/tmp/foo.shp','w',schema={'properties': schema_props, 'geometry': 'Polygon'}, driver = 'ESRI Shapefile')

5.3.4. 坐标和几何类型

矢量数据可以定义为二维或三维的结构。

如果你写一个三维坐标 (X, Y, Z) 元组到2D文件( Point 几何模式), Z 值就不会显示。

如果你写一个二维坐标 (x, y) 元组到3D文件( 3D Point 几何模式),默认的 Z 值就是 0