Reading data in a SpreadsheetDocument from MemoryStream - c#

I have a page on my site where a user can upload a XLSX spreadsheet. This is a .NET Core web application using the DocumentFormat.OpenXml (2.15.0) NuGet package.
I'm trying to read through each row in the spreadsheet they upload and do something with that data. I'm trying to do this without saving a physical file by copying the file to a MemoryStream, then reading the file from that stream, but not sure if that's possible.
The problem is that when reading the doc from the stream, it's like there's no data in the spreadsheet
Here's what I have:
using (var memoryStream = new MemoryStream())
{
await viewModel.SpreadsheetFile.CopyToAsync(memoryStream).ConfigureAwait(false);
// confirm that copying to memory stream worked correctly
var fileBytes = memoryStream.ToArray();
string s = Convert.ToBase64String(fileBytes);
using (SpreadsheetDocument document = SpreadsheetDocument.Open(memoryStream, true))
{
WorkbookPart workbook = document.WorkbookPart;
WorksheetPart worksheet = workbook.WorksheetParts.First();
SheetData sheetData = worksheet.Worksheet.Elements<SheetData>().First();
string text;
// no rows, doesn't enumerate here
foreach (Row r in sheetData.Elements<Row>())
{
foreach (Cell c in r.Elements<Cell>())
{
text = c.CellValue.Text;
// do stuff
}
}
}
}
I added a couple lines to read bytes from the memory stream just to confirm that it's working, which it is.
But when I try to create a SpreadsheetDocument from the memory stream and read the sheet data, it's just empty, it doesn't enumerate through the rows.
The code to read the sheet data I got from here: https://learn.microsoft.com/en-us/office/open-xml/how-to-parse-and-read-a-large-spreadsheet
Is this possible, or am I just doing this wrong?

You need to set memory stream to zero after reading to it. Change code to this:
await viewModel.SpreadsheetFile.CopyToAsync(memoryStream).ConfigureAwait(false);
memoryStream.Position = 0;

Related

Modifed word document not saving in memorystream

I am getting a word document from SharePoint using Microsoft graph API as a stream and changing some content in that file and downloading the saved content as a file but when I open the file, the modified content is not available. The downloaded file still shows the original content.
using (var memoryStream = new MemoryStream())
{
templateStream.Position = 0;
// Copying the stream that I've got into memory stream
await templateStream.CopyToAsync(memoryStream).ConfigureAwait(false);
memoryStream.Position = 0;
using (var wordDocument = WordprocessingDocument.Open(memoryStream, true))
{
RevisionAccepter.AcceptRevisions(wordDocument);
var document = wordDocument.MainDocumentPart.GetXDocument();
var content = document.Descendants(W.p).ToList();
//based on the dictionary I've I am replacing the contents of the file
foreach (var field in dataDictionary)
{
var regex = new Regex(field.Key, RegexOptions.IgnoreCase);
OpenXmlRegex.Replace(content, regex, field.Value.ToString(), null);
}
//not showing the modified content
wordDocument.Save();
//this is also not updating the memorystream variable with the modified content
wordDocument.MainDocumentPart.Document.Save();
memoryStream.Position = 0;
await memoryStream.FlushAsync().ConfigureAwait(false);
}
var result = memoryStream.ToArray();
memoryStream.Flush();
return result;
}
once I got the byte array from the above code I am downloading the file using this line from my controller
return File(returnResponse, System.Net.Mime.MediaTypeNames.Application.Octet, $"Test-
{System.DateTime.Now}.docx");
What am I doing wrong?
As outlined in this answer you need to call PutXDocument() method on the MainDocumentPart for your changes to be successfully reflected, because currently, you are making changes but not commiting them to the required document.

How to read incoming excel file in base64 and extract their data in C# asp.net

I am making an API using C# that takes excel files and transforms and saves its data to database.
I am transforming the excel sheet to base64 and then convert it using epplus to excel sheet.
Problem:
I want to access the sheet without having to save the file.
My Code so far:
public List<ApplicantEngExamBO> receiveAndSaveApplicantData(string database64, int exam_ID)
{
//converting file to byte[]
byte[] byteArray = Convert.FromBase64String(database64);
using (MemoryStream memStream = new MemoryStream(byteArray,0,byteArray.Length))
{
ExcelPackage package = new ExcelPackage(memStream);
package.Load(memStream);
//Just testing if it got any correct data
//It is not working
byte[] data = package.GetAsByteArray("ID");
var res = new List<ApplicantEngExamBO>();
foreach (var d in data)
{
res.Add(new ApplicantEngExamBO { studID = (int)d });
}
//return package;
return res;
}
}
How can we read the contents of the sheet without saving it, what to do next to get the data ? Other columns include "email".

Worksbook saved with stream is broken

recently I was trying to save Aspose.Cells.Workbook to stream with
private Stream GetWorkbook()
{
// processing workbook here
// ...
// saving to stream
return workbook.SaveToStream();
}
private void Save()
{
using (stream = GetWorkbook())
using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
stream.CopyTo(fileStream);
}
}
But when I'm trying to open generated .xlsx file Excel sends me an error that file is corrupted.
SaveToStream() method will only save your workbook in XLS format. So you should not use this method but use the following code to save your workbook in memory stream object. It should fix your issue.
C#
//Load your Excel file
Workbook wb = new Workbook(yourFile);
//Create memory stream object
MemoryStream ms = new MemoryStream();
//Determine the save format
SaveFormat svfmt = (SaveFormat)wb.FileFormat;
//Save the workbook to memory stream
wb.Save(ms, svfmt);
Note: I am working as Developer Evangelist at Aspose

How to read two sheet from CSV file

I have two sheets in CSV excel file which I upload using the following code. But from this code it reads only the first sheet. Even httpRequest.Files.Count returns only 1. How to read both sheet of the file
var httpRequest = HttpContext.Current.Request;
if (httpRequest.Files.Count > 0)
{
foreach (string file in httpRequest.Files)
{
long dataSourceId = 1;
var postedFile = httpRequest.Files[file];
var filePath = HttpContext.Current.Server.MapPath("~/" + postedFile.FileName);
//postedFile.SaveAs(filePath);
Stream stream = postedFile.InputStream;
byte[] fileData = null;
using (var binaryReader = new BinaryReader(postedFile.InputStream))
{
fileData = binaryReader.ReadBytes(postedFile.ContentLength);
}
Stream strrr = new MemoryStream(fileData);
}
}
From what I can tell CSV files aren't workbooks like Excel files, so you won't be about to read CSV file with two sheets as two entities on a single file. This is why I came to that conclusion:
http://network.ubotstudio.com/forum/index.php/topic/3236-save-in-multiple-sheets-in-a-csv-file/
You have two options: 1) Create multiple CSV files with the needed data and read from them individually OR 2) Use an Excel file that is formatted to handle these multiple sheet features.

Is it possible to write a packaging.package to a stream without having to save it to a file first?

I have a System.IO.Packaging.Package in memory (it is a WordprocessingDocument) and want to stream it down to browser to save it. The word document has been modified by the MVC-based application and the resulting file has been modified for the current request.
I understand the package represents a 'zip' file containing a number of parts. These parts include headers, footers and main body document. I've modified each individually and now want to stream the package back to the user.
I can get the individual part streams... package.GetPart(new Uri("/word/document.xml", UriKind.Relative)).GetStream()
However I'm missing how to get an output stream on the entire document (package)- without writing to the file system.
Thanks in advance
No- what I think I need is something like this... I've already read in the template document and made modifications in memory. Now I want to stream a modified document (leaving the template un-touched) back to the user.
MemoryStream stream = new MemoryStream();
WordprocessingDocument docOut =
WordprocessingDocument.Create( stream, WordprocessingDocumentType.Document);
foreach (var part in package.GetParts())
{
using (StreamReader streamReader = new StreamReader(part.GetStream()))
{
PackagePart newPart = docOut.Package.CreatePart(
part.Uri, part.ContentType );
using (StreamWriter streamWriter = new StreamWriter(newPart.GetStream(FileMode.Create)))
{
streamWriter.Write(streamReader.ReadToEnd());
}
}
}
Unfortunately- this produces a 'corrupt' word document...
OpenXmlPackage.Close Method saves all changes in all parts to the underlying store. If you opened the package from a stream, just use that stream:
public Stream packageStream() {
var ms = new MemoryStream();
var wrdPk = WordprocessingDocument.Create(ms, WordprocessingDocumentType.Document);
// Build the package ...
var docPart = wrdPk.AddMainDocumentPart();
docPart.Document = new Document(
new Body(new Paragraph(new Run(new Text("Hello world.")))));
// Flush all changes
wrdPk.Close();
return ms;
}

Categories