본문 바로가기
Web Study/React 관련

파일 업로드와 파일 저장... 이진 데이터 다루기

by 쿠리의일상 2023. 8. 22.

파일 업로드

const importFile = async (e) => {
	// input[type='file'] 로 들어오는 내용
    const files = Array.from(e.target.files);
    
    // 위 내용을 FileReader의 readAsDataURL 로 읽어와준다.
    const reader = new FileReader();
    reader.readAsDataURL(files[0]);
    
    // reader.result 는 readAsDataURL 로 읽어왔으므로 base64 타입을 띄게 된다.
    reader.onload = async () => {
      const url = "-";
      // base64 를 ArrayBuffer -> Uint8Array 로 읽어와줘야 dicomParser 사용이 가능
      const dataSet = dicomParser.parseDicom(b64toUint(reader.result));
      
      let patientId = dataSet.string("x00100020");
      let studyDate = dataSet.string("x00080020");
      let seriesTime = dataSet.string("x00080031");
      let instanceNumber = dataSet.string("x00200013");
      
      await axios
        .post(
          url,
          {
            patientId: patientId,
            studyDate: studyDate,
            seriesTime: Math.floor(parseFloat(seriesTime)),
            instanceNumber: instanceNumber,
            dcmBase64: reader.result,
          },
          // dicom 파일을 base64 타입으로 다룰 것이므로 application/octet-stream 으로 컨텐츠 타입을 지정해준다.
          { "Content-Type": "application/octet-stream", withCredentials: true }
        )
        .then((response) => {
          console.log("서버 성공 시 응답 데이터 : ", response.data);
        });
    };
  };

이 짧은 내용을 며칠을 삽질했는지 모르겠다 ...

이미지나 영상이 아닌 다이콤 파일이라 base64와 Blob, File, Uint8Array 등 다양한 방식으로 데이터를 다뤄볼 수 있었다 ^^...;

 

하다가 잘 안풀려서 아예 파일 구조를 뜯어보자! 싶어서 추출한 base64

base64

base64는 간략하게 쓰자면 아스키 코드 64개(64진법)으로 정리한 파일이다.

data:application/octet-stream;base64, 이후에 정보가 들어간다.

 

ArrayBuffer

Uint8Array 로 변환하기 전 거쳐야 하는 버퍼로 읽을 수 없는 문자들로 구성되어 있다.

그래서 Uint8Array 로 변경해줘야 다룰 수 있나보다.

 

Uint8Array

이름처럼 보다시피 양수 정수로 이루어져 있는 배열이다. 아스키 코드를 양수로 바꿔놓은거라고 보면 된다.

 

 

// base64 를 Uint8Array 로 바꿔주는 함수
function b64toUint(b64Data) {
  // base64 파일 형식의 경우 데이터 앞에 Content Type 과 파일 형식이 , 로 구분되어 있으므로
  // data:application/octet-stream;base64, ~~~
  // 데이터를 추출하기 위해선 ,를 기준으로 나눠줘야 한다.
  // 혹시라도 분리된 파일 형식이 들어올 경우 아래의 분기문으로 걸러줌
  let imageData;
  const b64Split = b64Data.split(",");
  if (b64Split[1] !== undefined) {
    imageData = atob(b64Split[1]);
  }
  
  // base64 를 이진 데이터 배열인 ArrayBuffer,
  // 그 데이터를 다루기 위한 TypedArray인 Uint8Array로 바꾸는 과정
  const arraybuffer = new ArrayBuffer(imageData.length);
  const view = new Uint8Array(arraybuffer);
  for (let i = 0; i < imageData.length; i++) {
    // 문자를 아스키코드로 변경해주는 charCodeAt() 메서드와 비트 연산자 &, 0xff(16진수) 사용하여
    // 음수를 양수로 바꿔주어 양수값을 배열에 저장해준다.
    view[i] = imageData.charCodeAt(i) & 0xff;
  }

  return view;
}

 

파일 저장

const saveFile = async (e) => {
    const url = `-`;
    const res = await axios.get(url);

    const uInt8 = b64toUint(res.data[0]);
    
    // new Blob([Uint8Array]) 로 블롭 생성
    const blob = new Blob([uInt8]); 
    const blobUrl = window.URL.createObjectURL(blob);
    
    const a = document.createElement("a");
    a.href = blobUrl;
    a.download = "download.dcm";
    document.body.appendChild(a);
    a.click(); // 강제로 실행
    a.remove();
    
    window.URL.revokeObjectURL(blobUrl); // 해제 해줘야 함
  };

블록 객체는 배열 형태로 Uint8Array 를 넣어줘서 만들어줄 수 있다.

블롭으로 만들면 window.URL.createObjectURL 로 해당 파일을 인터넷 상에서 접근이 가능한 URL 로 만들어줄 수 있게 된다. 그래서 임의의 a태그를 만들고 그 href  속성 안에 그 url을 넣어주면 다운로드 할 수 있는 형태가 된다.

 

'Web Study > React 관련' 카테고리의 다른 글

리액트 최적화 - react-icons 라이브러리  (0) 2023.09.13
Suspense를 사용하기에 앞서  (0) 2023.09.05
웹 페이지 최적화의 종류  (0) 2023.07.25
Custom Hooks  (0) 2023.07.21
React 컴포넌트 설계에 대해..  (0) 2023.07.18