2

I have a page to download a file from the Postgres database. Now I can hit the following URL to view the file content present in the database(stored as bytes)-HTTP://sandbox4.wootz.io:8080/api/blob/1/UploadFile/hope%20real.txt

Since the data is stored in a column of type bytes(byte array) when I click the download button it downloads the file and when I see its contents it is displayed as a byte array.

file.txt(contents)

[\x58595a5052415445454b3123473b4c534e44204e474f49574853474849444748445348474d70253335]

download functionality

  axios({
      url: 'api/store/blob/UploadFile/' + data.chosenfile,
      method: 'GET',
      headers: {'session_id': data.sessionid},
      responseType: 'arraybuffer'
    }).then(response => {
console.log(response.data); //displays nothing (empty)
var fileURL = window.URL.createObjectURL(new Blob([response.data]));
      console.log('fileURL is'+fileURL)
      var fileLink = document.createElement('a');
      console.log('fileLink is'+fileLink)
      fileLink.href = fileURL;
      fileLink.setAttribute('download', data.chosenfile);
      document.body.appendChild(fileLink);
      fileLink.click();
)

console.log of the response object

{"data":{},"status":200,"statusText":"OK","headers":{"access-control-allow-origin":"*","connection":"keep-alive","content-length":"86","content-type":"text/html; charset=utf-8","date":"Mon, 06 Jul 2020 18:22:23 GMT","etag":"W/\"56-Vaz0hG1/FIgtEurgvK+wOU+4F4M\"","x-powered-by":"Express"},"config":{"url":"api/store/blob/UploadFile/hope real.txt","method":"get","headers":{"Accept":"application/json, text/plain, */*","Access-Control-Allow-Origin":"http://localhost","session_id":"c5b3b878-771e-4472-84eb-6de15686effa"},"transformRequest":[null],"transformResponse":[null],"timeout":0,"responseType":"arraybuffer","xsrfCookieName":"XSRF-TOKEN","xsrfHeaderName":"X-XSRF-TOKEN","maxContentLength":-1},"request":{}}

Uploadfile part of my code(this is how the files was uploaded to database)

function readFileAsync(file) {
  return new Promise((resolve, reject) => {
    let reader = new FileReader();

    reader.onload = () => {
      var base64Url = reader.result; 
      console.log(base64Url) //ENITRE BASE64 URL 
     
     
      resolve(base64Url.substr(base64Url.indexOf(',') + 1)); //will return only the base64string part from the base64 url
    };

    reader.onerror = reject;

    reader.readAsDataURL(file); 
  })
}

async function uploadFile(path, data) {
  try {
    
    let base64string = await readFileAsync(data.chosenfile);
    console.log('base64 content  is'+ base64string)

    let response = await axios({
      method: 'post',
      url: 'api/store/blob' + path,
      headers: {'session_id': data.sessionid},
      data: {"id":data.chosenfile.name, "file":   base64string }
    });    

    if (response.status == 200) {
      console.log(response.status);
    }
    return response.data;
  } catch (err) {
    console.error(err);
  }
}

what am i doing wrong? why am i getting the file contents as [\x58595a5052415445454b3123473b4c534e44204e474f49574853474849444748445348474d70253335] ? What should I do to get the actual file's content in the downloaded file?

NOTE:With respect to the upload part, I am using the same strategy for all kind of files(excel documents,txt files etc) which is encoding it to base64 encoded string before passing it in the axios post payload.Now this payload is passed to another project called data-manager (interacts with postgres database).so when this data-manager project recieves the payload that i sent, it converts it to bytes [] before inserting to the table column of type bytea.So ultimately when i download any file from this table i will get the file contents also in bytea format.

Vignesh Swaminathan
  • 319
  • 1
  • 9
  • 24

1 Answers1

1

Your file is a correct ASCII text file with content [\x58595a5052415445454b3123473b4c534e44204e474f49574853474849444748445348474d70253335] literally.
That you get this content when you download it is perfectly fine, since it's what this file's content is.

What you want is to parse that content from the Hex representation they used to an actual ArrayBuffer to finally read that again as UTF-8 text (or any encoding respecting ASCII).

This has to be done after you do download the file and read it as text.
You first extract the actual bytes sequence as Hex from that [\x - ] wrapper, then you split the resulting string at every two chars to get hex values of every bytes, and finally you parse it into an Uint8Array to get back the original data:

// for StackSnippet we need to hardcode the response
// OP would have to make its request return that string
const response = { data: String.raw`[\x58595a5052415445454b3123473b4c534e44204e474f49574853474849444748445348474d70253335]` };
// .then( (response) => {
  const encoded_text = response.data;
  // remove leading "[\x" and final "]"
  const encoded_data = encoded_text.slice( 3, -1 );
  // split at every two chars, so we can get 0xNN, 0xNN
  const hex_bytes = encoded_data.match( /.{2}/g );
  // as numbers (0 - 255)
  const num_bytes = hex_bytes.map( (hex) => parseInt( hex, 16 ) );
  // wrap in an Uint8Array
  const view = new Uint8Array( num_bytes );
  
  // from there you can generate the Blob to save on disk
  download( new Blob( [ view ] ), "file.txt" );

  // but if you want to read it as UTF-8 text, you can:
  const as_text = new TextDecoder().decode( view );
  console.log( as_text );
// } );

function download( blob, filename ) {
  const anchor = document.createElement( "a" );
  anchor.href = URL.createObjectURL( blob );
  anchor.download = filename;
  anchor.textContent = "click to download";
  document.body.append( anchor );
}
Kaiido
  • 123,334
  • 13
  • 219
  • 285
  • this is working fine for text documents,but in the database i also have other kind of files(excel documents etc) which were actually enocded to base64 format using reader.readAsDataURL(file); – Vignesh Swaminathan Jul 07 '20 at 03:02
  • and from this base64 url i took out only the url part and not the header using resolve(base64String.substr(base64String.indexOf(',') + 1)); – Vignesh Swaminathan Jul 07 '20 at 03:03
  • Why don't you use the same strategy for both kind of files? (either all to b64, or all to hex). How do you know which has been converted to b64 and which has been converted to hex? I can't help you much here... Converting from b64 is quite easy too, and there are many answers already about it, but I think you are facing a more fundamental design problem here that only you can solve. – Kaiido Jul 07 '20 at 03:12
  • i have updated my question with the upload file part.Please help? – Vignesh Swaminathan Jul 07 '20 at 03:12
  • You can't get the result you said you have from the code in your edit. Please rollback this edit and ask an other question if you have more than what I have already answered to. Ps: my code would work with any binary data encoded the way you said it was encoded in the first revision of your question. – Kaiido Jul 07 '20 at 03:14
  • So for every files you get it as hex from your server? Then the solution in this answer will work. The download part is done before reading as text, that part is only for the demo here, as written in the comments of the snippet. – Kaiido Jul 07 '20 at 03:37
  • hi thanks you soo much for your answer it is working for all kinds of files.But i have to manually change the file extension type in the line download( new Blob( [ view ] ), "file.txt" );. example txt to xlsx? how to get the file type ? Note i am iam only sending the base64 string and not the entire base64url(contains header info) to the database.So how to get the file type? – Vignesh Swaminathan Jul 07 '20 at 03:42
  • oO From here there is no way. For some files you could look at the file signature but htere is no way to tell a csv from a txt, or even an xlsx from a zip, so once again that's your design, that's your job I can't do it for you (but it seems you already have it when you fetch the resource don't you?) – Kaiido Jul 07 '20 at 03:45
  • actually before uploading iam encoding it to a base64url- data:text/plain;base64,ICAgIGFwaV9zdWJtaXQgJ3BlcnNvbk9uYm9hcmQnLA== – Vignesh Swaminathan Jul 07 '20 at 03:50
  • but in the axios post iam not sending the enitre base64url itself (just the part after the comma) – Vignesh Swaminathan Jul 07 '20 at 03:52
  • example-ICAgIGFwaV9zdWJtaXQgJ3BlcnNvbk9uYm9hcmQnLA== – Vignesh Swaminathan Jul 07 '20 at 03:52
  • if i SEND the base64 url itself directly in the axios payload for the post, then the post will happen but the blob column value(bytea) in the table is showing NULL – Vignesh Swaminathan Jul 07 '20 at 03:54
  • so thats why i removed the data:text/plain;base64, part before sending it to the payload for the axios post – Vignesh Swaminathan Jul 07 '20 at 03:57