Shapefile
editA shapefile is the format of GIS software and of the open data of public agencies. It is a set of files with the same name: .shp holds the geometries, .dbf the attributes, .shx an index, .cpg the encoding of the attributes and .prj the coordinate system. They are often downloaded as a zip file.
Read a shapefile
Shapefile.Read reads the .shp file and the .dbf, .cpg and .prj files next to it:
// Reads points.shp with the attributes of points.dbf, decoded with the encoding of points.cpg
var features = Shapefile.Read("TestData/shapefile/points.shp");
Assert.Equal("points", features.Name);
var paris = features[0];
Assert.Equal(new GeoPosition(2.3522, 48.8566), ((GeoPoint)paris.Geometry!).Position);
Assert.Equal("Paris", paris.Properties["name"]);
Assert.Equal(2_102_650.0, paris.Properties["population"]); // Numbers are doubles
Assert.Equal(true, paris.Properties["capital"]);
Assert.Equal(new DateOnly(1952, 1, 31), paris.Properties["founded"]);Shapefile.ReadZip reads a zip file. When the archive holds several shapefiles, give the name of the one to read:
// A shapefile downloaded as a .zip archive
using var zip = File.OpenRead("TestData/shapefile/countries.zip");
var features = Shapefile.ReadZip(zip);
Assert.Equal("countries", features.Name);
var polygon = (GeoPolygon)features[0].Geometry!;
Assert.HasCount(2, polygon.Rings); // The exterior ring and a hole
Assert.True(polygon.Contains(new GeoPosition(5, 5)));- The Name of the collection is the name of the file.
- The geometries are points, multipoints, lines and polygons, with their Z values as altitudes and their M values as measures. An M value below -1038, the "no data" value of the format, is no measure. The rings of the polygons are grouped into polygons and holes by their orientation, and by their nesting when the file has the wrong orientation.
- The attributes are a
string, adouble, aboolor aDateOnly, by the type of their field. An empty value isnull. Deleted records are skipped. The features have no Id. - The encoding of the attributes comes from the
.cpgfile, or else from the header of the.dbffile. UTF-8, ISO-8859-1 and Windows-1252 are always supported; the other code pages need a provider, such asCodePagesEncodingProvider, registered by your application. Set Encoding when a file declares a wrong encoding. - The
.prjfile gives the CoordinateReferenceSystem of the features, ornullwhen there is none or it is not supported. The positions are those of the file, in meters for a shapefile in UTM or Lambert 93: set TransformToWgs84 to convert them to longitudes and latitudes. See coordinate reference systems.
Write a shapefile
Shapefile.Write writes the .shp, .shx, .dbf, .cpg (UTF-8) and .prj (WGS 84) files, and Shapefile.WriteZip writes them to a zip file:
var features = new GeoFeatureCollection
{
new(new GeoPoint(new GeoPosition(2.3522, 48.8566)), new Dictionary<string, object?> { ["name"] = "Paris", ["population"] = 2_102_650 }),
new(new GeoPoint(new GeoPosition(-0.5792, 44.8378)), new Dictionary<string, object?> { ["name"] = "Bordeaux", ["population"] = 261_804 }),
};
// Writes cities.shp, cities.shx, cities.dbf, cities.cpg and cities.prj
var directory = Directory.CreateTempSubdirectory();
Shapefile.Write(features, Path.Combine(directory.FullName, "cities.shp"));
// Or a .zip archive of these files
using var zip = new MemoryStream();
Shapefile.WriteZip(features, zip, "cities");- A shapefile holds one type of geometry: points, lines or polygons. Mixing them, or writing a GeoGeometryCollection, throws an
ArgumentException. Write each type to its own shapefile. - When a position has an altitude, every position is written with one, and 0 for those that have none.
- When a position has a measure, the M values are written: in the Z shapes when there are altitudes, else in the M shapes (PointM, MultiPointM, PolyLineM, PolygonM). The positions without measure get the "no data" value. The times are not written.
- The fields are the properties of the features. Their names are cut to 10 characters and made unique, as GDAL does. The text values are cut to 254 bytes, before a UTF-8 sequence that does not fit whole. A field whose values have different types is written as text.
- The identifiers are not written: shapefiles have none.
- The overload that writes to streams does not write the
.cpgfile: writeUTF-8to it yourself, so other programs read the attributes with the right encoding.