과정을 즐기자

바이너리 데이터를 처리하는 방법 본문

Spring

바이너리 데이터를 처리하는 방법

320Hwany 2023. 10. 28. 22:26

바이너리 데이터는 컴퓨터가 이해하기 쉬운 형식의 데이터로 일련의 0과 1로 표현됩니다.

이러한 바이너리 데이터는 텍스트 데이터에 비해 효율적으로 저장되며 데이터를 더 빠르게 전송할 수 있습니다.

기계가 읽을 수 있는 언어이기 때문에 빠른 처리가 가능하고 오류가 발생할 가능성이 적어집니다.

이러한 바이너리 데이터로는 이미지(JPEG), 오디오(MP3), 동영상(MP4) 등이 있습니다.

이번 글에서는 이러한 바이너리 데이터를 처리하는 방법에 대해 작성해보려고 합니다.

인코딩 방식

바이너리 데이터를 처리하는 방법 중 하나로 Base64를 사용하는 인코딩 방식이 있습니다.

Base64는 바이너리 데이터를 아스키 코드 일부와 일대일로 매칭되는 문자열로 단순 치환하는 인코딩 방식입니다.

즉, Base64를 사용하여 바이너리 데이터를 문자열로 다룰 수 있도록 만들어주는 것입니다.

Base64로 인코딩하면 UTF-8과 호환 가능한 문자열을 얻을 수 있습니다.

 

Base64를 사용할 때의 장점은 텍스트 형식으로 포함될 수 있다는 것입니다.

즉, 이미지 파일을 Base64로 인코딩하여 문자열로 취급하여 Json 형식으로 다른 문자열 데이터와 같이 보낼 수 있다는 것입니다.

또한 전송이 안정적이며 데이터 호환성이 좋다는 장점도 있습니다.

사용 예시를 살펴보면 URL 포함된 바이너리 데이터를 안전하게 처리하기 위해 사용되며 바이너리 데이터 처리를 위한

HTTP 요청 및 응답에도 사용됩니다. 그리고 JWT는 Header, Payload, Signature 3부분으로 나뉘는데 

Json 형태인 각 부분은 Base64로 인코딩되어 표현됩니다 

 

하지만 오늘날 데이터를 실시간으로 주고 받는 환경에서는 Base64를 거의 사용하지 않습니다.

왜냐하면 Base64로 인코딩된 데이터는 원래의 바이너리 데이터보다 더 큽니다.

이 때문에 실시간으로 대용량 데이터를 전송 및 저장할 때는적합하지 않은 방식입니다. 

MultipartFile, InputStream을 사용한 업로드

이어지는 내용은 Spring 프레임워크를 사용할 때의 예시입니다.

Spring Guide에서 제시하는 파일 업로드 처리 방식을 살펴보겠습니다.

여기서 주목해서 봐야할 것은 MultipartFile 인터페이스와 InputStream 추상 클래스입니다.

MultipartFile은 Spring 프레임워크에서 파일 업로드를 처리하기 위한 인터페이스입니다.

MultipartFile을 사용하면 클라이언트로부터 업로드된 파일을 쉽게 처리할 수 있습니다.

파일 업로드를 위한 복잡한 작업을 추상화하고 단순화 시켜주기 때문입니다.

클라이언트가 바이너리 데이터를 보내면 서버에서는 MultipartFile 객체로 변환하여 처리합니다.

public interface MultipartFile extends InputStreamSource {

    String getName();

    @Nullable
    String getOriginalFilename();
    
    @Nullable
    String getContentType();

    boolean isEmpty();

    long getSize();
    
    byte[] getBytes() throws IOException;

    @Override
    InputStream getInputStream() throws IOException;

    default Resource getResource() {
       return new MultipartFileResource(this);
    }

    void transferTo(File dest) throws IOException, IllegalStateException;
    
    default void transferTo(Path dest) throws IOException, IllegalStateException {
       FileCopyUtils.copy(getInputStream(), Files.newOutputStream(dest));
    }

}

다음으로 Java에서 지원하는 InputStream 추상 클래스에 대해 알아보겠습니다.

InputStream은 바이트 기반 입력 스트림 최상위 추상 클래스입니다.  0, 1이 8개모인 바이트 단위의 데이터가 들어올 때

처리할 수 있도록 추상화 해놓은 클래스라고 생각하면 됩니다. InputStream에는 데이터 읽기와 관련된 메소드가 3개 있습니다.

읽기 동작을 할 때 파일 데이터 전체를 메모리에 로드하는 방식이 아니라 작은 단위로 나눠 순차적으로 읽어 디스크에 저장합니다.

public abstract int read() throws IOException;

public int read(byte b[]) throws IOException {
        ...
}

public int read(byte b[], int off, int len) throws IOException {
        ...
}

데이터 읽기 이외에도 특정 시점으로 돌아가거나 데이터가 얼마나 남았는 지를 보여주거나 연결을 해제할 수 있습니다.

 

파일 업로드에 대해 정리해보면 클라이언트가 바이너리 데이터를 서버로 전송하면 서버는 바이너리 데이터를 MultipartFile 객체로

변환한 후 InputStream을 이용해 파일 데이터 전체를 메모리에 로드하지 않고 작은 단위로 나눠 순차적으로 디스크에 저장하는

과정을 거칩니다.

이러한 방식으로 처리하여 대용량 파일을 업로드할 때 메모리 부하를 최소화하고 대용량 파일을 안정적으로 처리할 수 있습니다.

Resource를 이용한 파일 접근

Spring Guide에서 제시하는 파일을 읽어오는 방식을 살펴보겠습니다.

Resource 인터페이스는 Spring 프레임워크에서 파일 및 리소스 접근을 추상화한 인터페이스입니다.

public interface Resource extends InputStreamSource {

    boolean exists();

    default boolean isReadable() {
       return exists();
    }

    default boolean isOpen() {
       return false;
    }

    default boolean isFile() {
       return false;
    }

    URL getURL() throws IOException;

    URI getURI() throws IOException;

    File getFile() throws IOException;

  	...

}

이때 주목해야 할 점이 Resource는 파일 또는 리소스에 대한 참조 객체입니다.

예를들어 동영상 재생을 요청할 때 서버의 메모리에 동영상 파일 전체가 올라오는 것이 아니라 Resource 정보를 바탕으로

필요한 부분만큼 순차적으로 읽어 네트워크에 전송하는 것입니다.

 

정리

바이너리 데이터는 Base64를 이용하여 인코딩하여 문자열로 처리하여 다룰 수 있습니다. 하지만 원래의 바이너리 데이터보다

데이터의 크기가 더 크기 때문에 실시간으로 대용량 데이터를 전송해야할 경우에는 적합하지 않습니다.

 

Java 기반의 Spring 프레임워크를 사용한다면 MultipartFile, InputStream을 이용하여 파일 업로드를 처리할 수 있습니다.

MultipartFile은 파일 업로드를 위한 복잡한 과정을 추상화, 단순화하였고 InputStream은 스트림 방식으로 바이트 코드를

읽을 수 있도록 하였습니다. 이 과정에서 중요한 점은 파일 전체를 메모리에 로드하는 방식이 아니라 작은 단위로 나눠

순차적으로 디스크에 저장하는 방식이라는 것입니다. 

 

또한 파일 접근의 경우에도 Resource를 이용하여 파일, 리소스에 대한 참조 객체를 사용해 이 정보를 바탕으로

필요한 부분만큼 순차적으로 읽어 네트워크에 전송할 수 있습니다. 

 

참고한 자료

 

Getting Started | Uploading Files

To start a Spring Boot MVC application, you first need a starter. In this sample, spring-boot-starter-thymeleaf and spring-boot-starter-web are already added as dependencies. To upload files with Servlet containers, you need to register a MultipartConfigEl

spring.io

 

Java InputStream이란?

InputStream OutputStream을 실무에서 사용할 때면, 뭔가 알긴 알고 실제로 둘을 활용해 기능을 구현하는데는 전혀 문제가 없지만, 사용할때마다 찾아보게되고 뭔가 정확히 아는 것 같지는 않다라는 느

lannstark.tistory.com