locked
Compress RRS feed

  • Question

  • User-1499457942 posted

    Hi

     Is it possible to compress data before export to excel

    Thanks

    Sunday, April 29, 2018 2:53 PM

All replies

  • User347430248 posted

    Hi JagjitSingh,

    If you are using ASP.NET then you can try to use 'HTTP Compression'.

    protected void Page_Load(object sender, EventArgs e)
    	{
    
    		// Decide what format the data is requested in by examining the Querystring; e.g. thispage.aspx?ExportedDataFormat=XML&DisplaySchema=true
    		if (Request.QueryString["ExportedDataFormat"] != string.Empty)
    			exportedDataFormat = (ExportedDataFormatValue)Enum.Parse((typeof(ExportedDataFormatValue)), Request.QueryString["ExportedDataFormat"]);
    		else exportedDataFormat = ExportedDataFormatValue.XML;
    
    		// Does the caller want the Schema for the XML displayed (if it's XML)?
    		if (Request.QueryString["DisplaySchema"] != string.Empty)
    			exportedDataSchemaDisplay = (ExportedDataSchemaDisplayValue)Enum.Parse((typeof(ExportedDataSchemaDisplayValue)), Request.QueryString["DisplaySchema"]);
    		else exportedDataSchemaDisplay = ExportedDataSchemaDisplayValue.False;
    
    
    		// Get a full DataSet from code elsewhere (not shown)
    		DataSet report = myDataLayer.GetADataSet();
    
    		// Get a MemoryStream with the processed report in
    		MemoryStream memoryStream = ProcessReport(report);
    
    		// Send the stream of data to the Client (Optionally Compressed)
    		SendDataStream(memoryStream);
    	}
    	/// <summary>
    	/// If the user desires an XML report, then just spit out the passed in dataset
    	/// (with or without the Schema as appropriate). Otherwise pass off to
    	/// another modthod to spit out the HTML or Excel report.
    	/// </summary>
    	/// <param name="dataSet">DataSet containing the data to export.</param>
    	private MemoryStream ProcessReport(DataSet dataSet)
    	{
    		MemoryStream memoryStream = new MemoryStream();
    
    		if (exportedDataFormat == ExportedDataFormatValue.XML)
    		{
    			if (exportedDataSchemaDisplay == ExportedDataSchemaDisplayValue.False)
    				dataSet.WriteXml(memoryStream, XmlWriteMode.IgnoreSchema);
    			else dataSet.WriteXml(memoryStream, XmlWriteMode.WriteSchema);
    		}
    		else memoryStream = WriteOut(dataSet.Tables[0], memoryStream); // It's Excel or HTML
    		return memoryStream;
    	}
    	/// <summary>
    	/// Common Method to write out a Datatable as either HTML or as CSV (Excel)
    	/// </summary>
    	/// <param name="oDataTable">The Table to write out, complete with data.</param>
    	private MemoryStream WriteOut(DataTable oDataTable, MemoryStream memoryStream)
    	{
    		MemoryStream excelStream = new MemoryStream();
    		bool IsInCsvFormat = (exportedDataFormat == ExportedDataFormatValue.Excel);
    
    		using (StreamWriter streamWriter = new StreamWriter(excelStream))
    		{
    
    			StringBuilder oStringBuilder = new StringBuilder();
    			if (!IsInCsvFormat)
    			{
    				oStringBuilder.Append("<table class=\"report\"><tr>");
    			}
    
    			// Create Column Headers
    			foreach (DataColumn oDataColumn in oDataTable.Columns)
    			{
    				// Skip Byte columns altogether; unlikely to be valuable in a report (YMMV)
    				if (oDataColumn.GetType().ToString() == "System.Byte[]") continue;
    
    				if (IsInCsvFormat)
    				{
    					oStringBuilder.Append(oDataColumn.ColumnName);
    					if (oDataColumn != oDataTable.Columns[oDataTable.Columns.Count - 1]) oStringBuilder.Append(",");
    				}
    				else
    				{
    					oStringBuilder.Append("<th>");
    					oStringBuilder.Append(oDataColumn.ColumnName);
    					oStringBuilder.Append("</th>");
    				}
    			}
    			if (!IsInCsvFormat) oStringBuilder.Append("</tr>");
    
    			// Write the Header to our local excelStream
    			streamWriter.WriteLine(oStringBuilder.ToString());
    			oStringBuilder.Length = 0;
    
    			// Now Create the Rows
    			foreach (DataRow oDataRow in oDataTable.Rows)
    			{
    				if (!IsInCsvFormat) oStringBuilder.Append("<tr>");
    
    				foreach (DataColumn oDataColumn in oDataTable.Columns)
    				{
    					switch (oDataRow[oDataColumn.ColumnName].GetType().ToString())
    					{
    						case "System.DBNull":
    							if (!IsInCsvFormat) oStringBuilder.Append("<td>");
    							break;
    						case "System.String":
    							if (IsInCsvFormat)
    							{
    								oStringBuilder.Append("\"");
    								oStringBuilder.Append(oDataRow[oDataColumn.ColumnName].ToString().Replace("\"", string.Empty).Trim());
    								oStringBuilder.Append("\"");
    							}
    							else
    							{
    								oStringBuilder.Append("<td class=\"string\">");
    								oStringBuilder.Append(oDataRow[oDataColumn.ColumnName]);
    							}
    							break;
    						case "System.Byte[]":
    							// Skip this column
    							continue;
    						case "System.Int32":
    							if (!IsInCsvFormat) oStringBuilder.Append("<td class=\"int\">");
    							oStringBuilder.Append(oDataRow[oDataColumn.ColumnName]);
    							break;
    						case "System.DateTime":
    							if (!IsInCsvFormat) oStringBuilder.Append("<td class=\"datetime\">");
    							oStringBuilder.Append(oDataRow[oDataColumn.ColumnName]);
    							break;
    						case "System.Guid":
    							if (IsInCsvFormat) oStringBuilder.Append("\"");
    							else oStringBuilder.Append("<td class=\"guid\">");
    							oStringBuilder.Append(oDataRow[oDataColumn.ColumnName]);
    							if (IsInCsvFormat) oStringBuilder.Append("\"");
    							break;
    						default:
    							if (!IsInCsvFormat) oStringBuilder.Append("<td>");
    							oStringBuilder.Append(oDataRow[oDataColumn.ColumnName]);
    							break;
    					}
    
    					if (IsInCsvFormat)
    					{
    						if (oDataColumn != oDataTable.Columns[oDataTable.Columns.Count - 1]) oStringBuilder.Append(",");
    					}
    					else oStringBuilder.Append("</td>");
    				}
    
    				if (!IsInCsvFormat) oStringBuilder.Append("</tr>");
    
    				// Write the row to our local excelStream
    				streamWriter.WriteLine(oStringBuilder.ToString());
    				oStringBuilder.Length = 0;
    			}
    			if (!IsInCsvFormat)
    			{
    				streamWriter.WriteLine("</table>");
    				streamWriter.WriteLine(footerText);
    			}
    
    			streamWriter.Flush();
    
    			// Copy local excelStream to our MemoryStream before disposing of it
    			memoryStream.Write(excelStream.ToArray(), 0, Convert.ToInt32(excelStream.Length));
    		}
    		return memoryStream;
    	}
    	private void SendDataStream(MemoryStream memoryStream)
    	{
    		Response.Clear();
    		switch (exportedDataFormat)
    		{
    			case ExportedDataFormatValue.XML:
    				Response.AddHeader("Content-Type", "text/xml");
    				break;
    			case ExportedDataFormatValue.Excel:
    				Response.AddHeader("Content-Type", "application/vnd.ms-excel");
    				Response.AddHeader("Content-disposition", ": csv; filename=document_" + Guid.NewGuid().ToString("N") + ".csv");
    				break;
    			default:
    				break;
    		}
    
    		/* Uncomment the three lines below if you want a physical file written to the server for debugging purposes.
    		if (exportedDataFormat == ExportedDataFormatValue.XML) File.WriteAllBytes(Request.PhysicalApplicationPath + "Output.xml", memoryStream.ToArray());
    		else if (exportedDataFormat == ExportedDataFormatValue.Excel) File.WriteAllBytes(Request.PhysicalApplicationPath + "Output.csv", memoryStream.ToArray());
    		else File.WriteAllBytes(Request.PhysicalApplicationPath + "Output.html", memoryStream.ToArray());*/
    
    		// Use GZip compression if the Client supports it (all modern browsers do)
    		memoryStream = OptionallyCompressOutput(memoryStream);
    
    		// Send the reponse to the Client and quit out
    		Response.OutputStream.Write(memoryStream.ToArray(), 0, Convert.ToInt32(memoryStream.Length));
    		memoryStream.Close();
    		Response.End();
    	}
    
    	/// <summary>
    	/// Examine HTTP Headers, looking for gzip support from requesting Client.
    	/// If found, compress the stream using GZip compression. This works very well
    	/// as our stream is XML and so full of air. We also set the Content-Encoding header to
    	/// inform the client it needs to uncompress the data.
    	/// If no support found, return uncompressed stream and don't set any Content-Encoding header.
    	/// </summary>
    	/// <param name="streamToSend">The stream full of data to squash.</param>
    	private MemoryStream OptionallyCompressOutput(MemoryStream memoryStream)
    	{
    		// Examine the headers sent by the client to see if it accepts gzip compression
    		string acceptedTypes = Request.Headers["Accept-Encoding"];
    		string[] types = acceptedTypes.Split(',');
    		for (int i = 0; i < types.Length; i++)
    		{
    			string acceptEncodingValue = types[i].Trim().ToLower();
    			if (acceptEncodingValue.StartsWith("gzip") || acceptEncodingValue.StartsWith("x-gzip"))
    			{
    				Response.AppendHeader("Content-Encoding", "gzip");
    				using (MemoryStream compressedData = new MemoryStream())
    				{
    					using (System.IO.Compression.GZipStream compressedStream = new System.IO.Compression.GZipStream(compressedData, System.IO.Compression.CompressionMode.Compress))
    					{
    						byte[] data = memoryStream.ToArray();
    						compressedStream.Write(data, 0, data.Length);
    					}
    					memoryStream = new MemoryStream(compressedData.ToArray());
    					// We now have our original data all squashed up in our local memoryStream.
    				}
    			}
    		}
    		return memoryStream;
    	}

    Reference:

    1. ASP.NET: Exporting a report to Excel, with HTTP Compression
    2. ReportExampleWithCompression.zip

    Regards

    Deepak

    Monday, April 30, 2018 6:19 AM