How to save xlsx file from stream

Hi

I created a xlsx file from flexcel on my xdata server in a tmemorystream. How do I save that stream on my webclient to a xlsx file.

These posts might help you

My code on the xdata server:

 TDirectDownload = class
    FFilename: String;
    Data: String;
    ContentType: String;
  end;
function TReportService.DirectDownload(const ReportId: Integer; const ParamValues: string): TDirectDownload;
var
  lFileName, lFullPath: string;
  lFileStream: TFileStream;
  lOutStream: TStringStream;
  Dataset: TDataset;
  lTitle: string;
begin
  lTitle := '';
  lFileName := '';

  Dataset := GetData(ReportId, ParamValues, lFileName, lTitle);
  try
    CreateXLS(Dataset, lFileName, lTitle);
  finally
    Dataset.Free;
  end;

  result := TDirectDownload.Create;

  result.FFilename := lFileName;
  result.ContentType := 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
  lFullPath := TPath.Combine(SavePath, lFileName);

  if not TFile.Exists(lFullPath) then
    raise EFileNotFoundException.Create('The file was not found');

  // TXDATAOperationContext.Current.Response.Headers.AddValue('Content-type', 'application/pdf');
  // TXDATAOperationContext.Current.Response.Headers.AddValue('Content-Disposition', 'filename=' + lFileName);

  lFileStream := TFileStream.Create(lFullPath, fmOpenRead);
  try
    lFileStream.Position := 0;
    lOutStream := TStringStream.Create('');
    try
      TNetEncoding.Base64.Encode(lFileStream, lOutStream);
      lOutStream.Position := 0;
      result.Data := lOutStream.DataString;
    finally
      lOutStream.Free;
    end;
  finally
    lFileStream.Free;
  end;

end;

And on webcore:

class procedure TFileSupport.SaveEncoded64File(const aFileName, AData: string);
var
  FileData: WideString;
  FileLen: Integer;
  I: Integer;
  AB: TJSArrayBuffer;
  AV: TJSUInt8Array;
begin
  try
    FileData := window.atob(AData);
    FileLen := Length(FileData);
  except
    on E: Exception do
    begin
      console.log('ERROR: (Base64) File could not be decoded');
      raise Exception.Create('ERROR: (Base64) File could not be decoded');
    end;
  end;

  if (FileLen <> -1) then
  begin
    console.log('Retrieved (Base64) File: ' + IntToStr(Length(AData)) + ' bytes');
    console.log('Decoded (Base64) File: ' + IntToStr(FileLen) + ' bytes');
  end;

  AB := TJSArrayBuffer.new(FileLen);
  AV := TJSUInt8Array.new(AB);
  for I := 0 to FileLen - 1 do
    AV[i] := TJSString(FileData).charCodeAt(i);
  Application.DownloadBinaryFile(AV, aFileName);

end;

I'll leave you the exercise of creating the connecting core :slight_smile:

I am in the process of putting these all into some support libraries that I'll publish on github - some are there already (part formed).

It seems the download payload is encoded as a Base64 file. Why does the Content-Type header say it's a spreadsheet rather than something appropriate for a Base64 data file? It might make sense if you want the client side (a web browser) to open and display it somehow, but not if you just want to work with it or save it to a file as binary data.

As an aside, @wlandgraf it would be really nice if there was a setting somewhere that enabled this for a given payload. Stuff the data into a compressed stream, convert it to Base64, put it into another TStream of some kind (if needed), send it down, then unpack it and deliver it as a TMemoryStream to the Client. Something similar would go from Client to Server, but that might be a slightly different process. (It may be a file on the server and a TMemoryStream on the Client. I'm not working with actual files on the Client side, just in-memory data. The files are all stored remotely.)

The reason that the underlying file type is provided is so that receiving applications know what has been encoded. In this instance I am just saving it, but that might not always be the case.

1 Like

Hi Russel

Thanks for your help so far, on the client side I get the below error once it execute the following command

FileData := window.atob(AData);

DOMException: Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded

I retested this here but couldn't see an issue.
I'd recommend to log AData in the console and verify if this is the correct expected base64 data and if not, check the code you use to get AData.

I was wondering what the atob(...) function is.

Thanks all, I did come write everything is working now, I appreciate all your help

1 Like

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.