0

I have a project that need to take geometry data from DataBase and based on that data create KML file.

For small amout of data it create KML file, but when I try it to create for example 600.000 geo locations data and create KML file I get out of memory error.

To create KML file I use SharpKml library. Usualy I get this error when I try this code

var kml = new Kml { Feature = document };
KmlFile kmlFile = KmlFile.Create(kml, true);
var stream = new MemoryStream();
kmlFile.Save(stream);  <=== I think here
files.Add(new KeyValuePair<string, Stream>(fileName, stream));
return files;

Please help me or give me advice how can I solve this problem, are there any way to do this. I think I can use Azure blob storage to store this file by chunks. But how can I get this by chunks or how to save it by chunks.

Maybe the error is not related to Memory, maybe is about create KML, if there are any way to solve help me.

If you had a any experience with this problem please give me advice,

Thanks

I use this function to create KML file, If you have any suggestion please let me know.

      public List<KeyValuePair<string, Stream>> ExportToKml(List<dynamic> exportedData, string exportBy, string geometry)
        {
            var documentAll = new Document();

            List<KeyValuePair<string, Stream>> files = new();

            string fileNameAll = $"All_{exportBy}.kml";

            var providers = exportedData.Select(p => new { p.ProviderId, p.ProviderName }).Distinct().ToList();
            var technologies = exportedData.Select(t => new { t.TechCode, t.TechnologyName }).Distinct().ToList();

            foreach (var provider in providers)
            {
                foreach (var technology in technologies)
                {
                    dynamic providerTechCnties = exportedData.Where(c => c.ProviderId == provider.ProviderId
                                                    && c.TechCode == technology.TechCode).Distinct().ToList();

                    string fileName = $"{provider.ProviderName}_{technology.TechnologyName}_{exportBy}.kml";

                    if (providerTechCnties.Count != 0)
                    {
                        var document = new Document();

                        int entrance = 0;

                        Random _random = new();

                        byte byte_Color_R = Convert.ToByte(_random.Next(250)),
                             byte_Color_G = Convert.ToByte(_random.Next(250)),
                             byte_Color_B = Convert.ToByte(_random.Next(250)),
                             byte_Color_A = 225;

                        foreach (var kmlData in providerTechCnties)
                        {
                            CoordinateCollection coordinates = new CoordinateCollection();

                            Placemark placemark = new();
                            Placemark placemarkAll = new();

                            OuterBoundary outerBoundary = new();
                            Polygon polygon = new();
                            Point point = new();
                            LineString line = new();

                            var style = new Style();
                            var styleAll = new Style();

                            if (geometry == "polygon")
                            {
                                List<string> geomCoords = new();

                                if (kmlData.Coordinate is not null)
                                {
                                    string[] coordSplit = kmlData.Coordinate.Replace(' ', ',').Replace("),", ")")
                                        .Split(new string[] { "(", ")" }, StringSplitOptions.RemoveEmptyEntries);

                                    for (int i = 0; i < coordSplit.Count(); i++)
                                    {
                                        geomCoords.Add(coordSplit[i]);
                                    }
                                }

                                string[] coord = Array.Empty<string>();

                                if (geomCoords?.Count != 0) { coord = geomCoords[1]?.ToString().Split(','); }

                                for (int i = 0; i < coord.Length; i += 2)
                                {
                                    double lat = double.Parse(coord[i].ToString());
                                    double lon = double.Parse(coord[i + 1].ToString());
                                    coordinates.Add(new Vector(lon, lat));
                                }

                                outerBoundary.LinearRing = new LinearRing { Coordinates = coordinates };

                                polygon.Extrude = true;
                                polygon.AltitudeMode = AltitudeMode.ClampToGround;
                                polygon.OuterBoundary = outerBoundary;
                            }
                            else if (geometry == "point")
                            {
                                point.Coordinate = new Vector(Convert.ToDouble(kmlData.Lat), Convert.ToDouble(kmlData.Lon));
                            }
                            else if (geometry == "line")
                            {
                                List<string> geomCoords = new();

                                if (kmlData.Coordinate is not null)
                                {
                                    string[] coordSplit = kmlData.Coordinate.Replace(' ', ',').Replace("),", ")")
                                        .Split(new string[] { "(", ")" }, StringSplitOptions.RemoveEmptyEntries);

                                    for (int i = 0; i < coordSplit.Count(); i++)
                                    {
                                        geomCoords.Add(coordSplit[i]);
                                    }
                                }

                                string[] coord = Array.Empty<string>();

                                if (geomCoords?.Count != 0) { coord = geomCoords[1]?.ToString().Split(','); }

                                line.Coordinates = new CoordinateCollection();

                                for (int i = 0; i < coord.Length; i += 2)
                                {
                                    double lat = double.Parse(coord[i].ToString());
                                    double lon = double.Parse(coord[i + 1].ToString());

                                    line.Coordinates.Add(new Vector(lon, lat));
                                }
                            }

                            PropertyInfo[] pkmlDataProps = kmlData.GetType().GetProperties();

                            if (entrance == 0)
                            {
                                Dictionary<string, string> cntySimpleFields = new Dictionary<string, string>();
                                foreach (PropertyInfo pkmlDataProp in pkmlDataProps)
                                {
                                    if (pkmlDataProp.Name != "Coordinate") cntySimpleFields.Add(pkmlDataProp.Name, "string");
                                }

                                Schema cntySchema = new Schema();
                                Schema cntySchemaAll = new Schema();

                                foreach (var cntySimpleField in cntySimpleFields)
                                {
                                    SimpleField simpleField = new SimpleField
                                    {
                                        Name = cntySimpleField.Key,
                                        FieldType = cntySimpleField.Value
                                    };

                                    SimpleField simpleFieldAll = new SimpleField
                                    {
                                        Name = cntySimpleField.Key,
                                        FieldType = cntySimpleField.Value
                                    };

                                    cntySchema.AddField(simpleField);
                                    cntySchemaAll.AddField(simpleFieldAll);
                                }

                                document.AddSchema(cntySchema);
                                documentAll.AddSchema(cntySchemaAll);

                                entrance++;
                            }


                            placemark.ExtendedData = new ExtendedData();
                            placemarkAll.ExtendedData = new ExtendedData();

                            Dictionary<string, dynamic> cntySimpleDatas = new Dictionary<string, dynamic>();
                            foreach (PropertyInfo pkmlDataProp in pkmlDataProps)
                            {
                                if (pkmlDataProp.Name != "Coordinate") cntySimpleDatas.Add(pkmlDataProp.Name, pkmlDataProp.GetValue(kmlData, null)?.ToString());
                            }

                            SchemaData cntySchemaData = new SchemaData();
                            SchemaData cntySchemaDataAll = new SchemaData();

                            foreach (var cntySimpleData in cntySimpleDatas)
                            {
                                SimpleData simpleData = new SimpleData
                                {
                                    Name = cntySimpleData.Key,
                                    Text = cntySimpleData.Value
                                };

                                SimpleData simpleDataAll = new SimpleData
                                {
                                    Name = cntySimpleData.Key,
                                    Text = cntySimpleData.Value
                                };

                                cntySchemaData.AddData(simpleData);
                                cntySchemaDataAll.AddData(simpleDataAll);
                            }

                            placemark.ExtendedData.AddSchemaData(cntySchemaData);
                            placemarkAll.ExtendedData.AddSchemaData(cntySchemaDataAll);

                            style.Polygon = new PolygonStyle();
                            style.Polygon.ColorMode = ColorMode.Normal;
                            style.Polygon.Color = new Color32(byte_Color_A, byte_Color_B, byte_Color_G, byte_Color_R);

                            style.Balloon = new BalloonStyle();
                            style.Balloon.BackgroundColor = new Color32(byte_Color_A, byte_Color_B, byte_Color_G, byte_Color_R);

                            styleAll.Polygon = new PolygonStyle();
                            styleAll.Polygon.ColorMode = ColorMode.Normal;
                            styleAll.Polygon.Color = new Color32(byte_Color_A, byte_Color_B, byte_Color_G, byte_Color_R);

                            styleAll.Balloon = new BalloonStyle();
                            styleAll.Balloon.BackgroundColor = new Color32(byte_Color_A, byte_Color_B, byte_Color_G, byte_Color_R);

                            if (geometry == "polygon")
                            {
                                placemark.Geometry = polygon;
                                placemarkAll.Geometry = polygon;
                            }
                            else if (geometry == "point")
                            {
                                placemark.Geometry = point;
                                placemarkAll.Geometry = point;
                            }
                            else if (geometry == "line")
                            {
                                placemark.Geometry = line;
                                placemarkAll.Geometry = line;
                            }

                            placemark.AddStyle(style);
                            placemarkAll.AddStyle(styleAll);

                            document.AddFeature(placemark);
                            documentAll.AddFeature(placemarkAll);
                        }

                        document.Id = exportBy;
                        document.Name = fileName;

                        var kml = new Kml { Feature = document };

                        KmlFile kmlFile = KmlFile.Create(kml, true);

                        var stream = new MemoryStream();

                        kmlFile.Save(stream);
                        files.Add(new KeyValuePair<string, Stream>(fileName, stream));
                        
                    }
                }
            }

            documentAll.Id = exportBy;
            documentAll.Name = fileNameAll;

            var kmlAll = new Kml { Feature = documentAll };

            KmlFile kmlFileAll = KmlFile.Create(kmlAll, true);

            var streamAll = new MemoryStream();


                kmlFileAll.Save(streamAll);
                files.Add(new KeyValuePair<string, Stream>(fileNameAll, streamAll));
            

            return files;
        }
  • KML is XML format and is string that can be opened with any text editor. KML can be huge and the only library that can Read/Write huge XML is XmlReader/XmlWriter. If SharpKml is using a different Xml library is will not work. Your issue may be different and could be the amount of memory on your machine. Check Task Manager and see how much memory is being used. – jdweng Mar 18 '23 at 09:55
  • When memory is used up swap space on you hard drive is used which is slower than memory, but will prevent out of memory exceptions. Try increasing swap space : Go to the Start Menu and click on Settings. Type performance. Choose Adjust the appearance and performance of Windows. In the new window, go to the Advanced tab and under the Virtual memory section, click on Change. – jdweng Mar 18 '23 at 09:57
  • thank you for aswering. as I understand the problem happened in this line kmlFile.Save(stream); is there any way to save this by chunks not all once? – Hamlet Poghosyan Mar 18 '23 at 16:03
  • im not sure if I use XmlReader it will create correct KML file which I can open in QGIS? – Hamlet Poghosyan Mar 18 '23 at 16:04
  • Saving has nothing to do with issue. Saving is writing to a file. You have a memory issue. A memory stream in Net has only one set of pointers. If you are using the stream to write to a file you can load with a fixed size amount of data. Then set the position to zero and read the buffer. Then set position to zero and length to zero and fill again. – jdweng Mar 18 '23 at 18:37
  • XmlReader/Writer can create any type of xml. You have a memory issue due to the file being huge. You have to solve the memory issue by either adding more memory and/or increasing the virtual memory using swap space. – jdweng Mar 18 '23 at 18:44
  • at System.IO.MemoryStream.set_Capacity(Int32 value) at System.IO.MemoryStream.EnsureCapacity(Int32 value) at System.IO.MemoryStream.Write(Byte[] buffer, Int32 offset, Int32 count) at System.Xml.XmlUtf8RawTextWriter.FlushBuffer() – Hamlet Poghosyan Mar 19 '23 at 17:37
  • at SharpKml.Base.Serializer.SerializeElement(XmlWriter writer, XmlNamespaceManager manager, Element element) at SharpKml.Base.Serializer.ElementSerializer.SerializeElements(Element element, Type elementType) – Hamlet Poghosyan Mar 19 '23 at 17:38
  • at SharpKml.Base.Serializer.Serialize(Element root, Stream stream, XmlWriterSettings settings) at Wireless2020.WiROITMDB.Infrastructure.FileExport.KmlExporter .ExportToKml(List`1 exportedData, String exportB – Hamlet Poghosyan Mar 19 '23 at 17:38
  • FileExport\KmlExporter.cs:line 259 I get this error message in this line 259 it is the line of kmlFile.Save(streaml); is this out of memory exeption yes ? – Hamlet Poghosyan Mar 19 '23 at 17:39
  • The code is taking all the tags in the KML file and adding to a dictionary to return List>. A list of KeyValuePair is a dictionary. The file is huge and so is the stream returned. I've worked with KML before and went to a lot of trouble to avoid memory exceptions. The only way to avoid exception was to use XmlReader and only parse pieces of the KML at one time and not to parse the entire file. KML is used with maps and contains many layers of same location. I ended up parsing one layer at a time to avoid the memory exception. – jdweng Mar 19 '23 at 19:30
  • thank you very much, do you have some examples or a GitHub repo where I can check? – Hamlet Poghosyan Mar 20 '23 at 10:09
  • See : https://stackoverflow.com/questions/61607180/parse-big-xml-file-using-xmlreader?force_isolation=true I've answer lots of these questions and you can search "stackoverflow c# jdweng xml huge" – jdweng Mar 20 '23 at 10:18
  • so the possible solution is to add more memory yes? – Hamlet Poghosyan Mar 20 '23 at 11:12
  • Either add more memory or increase the Virtual Memory or parse smaller sections of the xml instead of the entire xml. – jdweng Mar 20 '23 at 11:35
  • thank you, I will try the way you say, if there are any solution already implemented for this case please send me, thank you very much ♥ – Hamlet Poghosyan Mar 20 '23 at 12:28

0 Answers0