Closed jengstro2 closed 4 months ago
I needed stream write support, so I was working on similar changes for writing. I think the method OpenStreamRead
should just be called OpenRead
; since the parameters are different, it can be an overload. Also, should I create a separate fork and pull request for the stream writing, or could they be added to this?
/// <summary>
/// Opens shapefile writer.
/// </summary>
/// <param name="shpStream">SHP file stream.</param>
/// <param name="shxStream">SHX file stream.</param>
/// <param name="dbfStream">DBF file stream.</param>
/// <param name="options">Writer options.</param>
/// <returns>Shapefile writer.</returns>
public static ShapefileWriter OpenWrite(Stream shpStream, Stream shxStream, Stream dbfStream, ShapefileWriterOptions options)
{
options = options ?? throw new ArgumentNullException(nameof(options));
if (options.ShapeType.IsPoint())
{
return new ShapefilePointWriter(shpStream, shxStream, dbfStream, options);
}
else if (options.ShapeType.IsMultiPoint())
{
return new ShapefileMultiPointWriter(shpStream, shxStream, dbfStream, options);
}
else if (options.ShapeType.IsPolyLine())
{
return new ShapefilePolyLineWriter(shpStream, shxStream, dbfStream, options);
}
else if (options.ShapeType.IsPolygon())
{
return new ShapefilePolygonWriter(shpStream, shxStream, dbfStream, options);
}
else
{
throw new ShapefileException("Unsupported shapefile type: " + options.ShapeType, "No File");
}
}
/// <summary>
/// Writes features to the shapefile.
/// </summary>
/// <param name="features">Features to be written.</param>
/// <param name="shpStream">SHP file stream.</param>
/// <param name="shxStream">SHX file stream.</param>
/// <param name="dbfStream">DBF file stream.</param>
/// <param name="projection">Projection metadata for the shapefile (content of the PRJ file).</param>
/// <param name="encoding">DBF file encoding (if not set UTF8 is used).</param>
public static void WriteAllFeatures(IEnumerable<IFeature> features, Stream shpStream, Stream shxStream, Stream dbfStream,
string projection = null, Encoding encoding = null)
{
if (features == null)
throw new ArgumentNullException(nameof(features));
var firstFeature = features.FirstOrDefault();
if (firstFeature == null)
throw new ArgumentException(nameof(ShapefileWriter) + " requires at least one feature to be written.");
var fields = firstFeature.Attributes.GetDbfFields();
var shapeType = features.FindNonEmptyGeometry().GetShapeType();
var options = new ShapefileWriterOptions(shapeType, fields)
{
Projection = projection,
Encoding = encoding
};
using (var shpWriter = OpenWrite(shpStream, shxStream, dbfStream, options))
{
shpWriter.Write(features);
}
}
OpenRead(...) overloaded with Stream option -> fine by me. Yeah, Stream write should be there also 👍
Thank you for your valuable input @jengstro2. I changed the method names to OpenRead()
and ReadAllFeatures()
. I added also tests for new methods. Please check if it's fine for you.
@FrankHileman, stream write support is also added. Can you review it?
There is one issue, unrelated to Streams specifically. There isn't any place to put the projection file using Streams. I haven't found a better solution, except to have yet another stream.
Good point, @FrankHileman. I've added projection stream parameter. Does it work for you?
Fix #41
Hello, in testing this I found a problem. Unlike the other streams, which are left open, the projection stream is closed. We should leave all streams open after the write operation. The problem is the use of a using statement, and a StreamWriter constructor. The StreamWriter constructor has a parameter called "leaveOpen", when set to true, will leave the stream open when the StreamWriter is disposed. We should set this to true.
internal ShapefileWriter(Stream shpStream, Stream shxStream, Stream dbfStream, Stream prjStream, ShapefileWriterOptions options)
: base(new DbfWriter(dbfStream, options?.Fields, options?.Encoding))
{
try
{
options = options ?? throw new ArgumentNullException(nameof(options));
ShapeType = options.ShapeType;
ShpWriter = CreateShpWriter(shpStream, shxStream);
if (!string.IsNullOrWhiteSpace(options.Projection) && prjStream != null)
{
using (var writer = new StreamWriter(prjStream))
{
writer.Write(options.Projection);
}
}
}
catch
{
DisposeManagedResources();
throw;
}
}
I wasn't sure if I should start a new issue...
using (var writer = new StreamWriter(prjStream, Encoding.UTF8, 1024, true)) { writer.Write(options.Projection); }
Stream input alternative for reading shp and dbf.