Search code examples
javascriptblobbytea

how to convert byte array to base64 encoded format?


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.


Solution

  • 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 );
    }