[JAVA] 파일 디스크에 바로 저장하기(RandomAccessFile)
[JAVA] 파일 디스크에 바로 저장하기(RandomAccessFile) — #JAVA소켓통신 #소켓통신 #소켓통신파일전송 #소켓통신파일 #개발자의도구들 AI스쿨 msa기반 java 백...
#JAVA소켓통신 #소켓통신 #소켓통신파일전송 #소켓통신파일 #개발자의도구들
AI스쿨 msa기반 java 백엔드 코스 중에 공부한 내용을 작성하였습니다
\* 현재 소켓통신 프로젝트를 진행중입니다. 전체적인 목차를 보시려면 여기에서 참고하세요
파일 저장 프로세스 변경
기존의 문제점
메모리 사용의 문제점
이전글을 통해서 파일을 주고 받는 과정에 대해서 설명한 바 있습니다. 하지만, 해당 구조의 문제점이 명확하여 실제로 사용할 수 없기에 파일 저장 프로세스를 다시 구축하였습니다.
기존 파일 저장의 문제점은 이렇습니다.
수신 클라이언트는 서버로 부터 받은 파일을 seq에 따라 메모리에 저장해두고, FileEnd 메세지가 올 때 해당 fileName을 참조하여 seq를 합쳐서 한번에 저장합니다. 이런 방식의 문제점은 명확한데 바로 메모리의 크기의 제한 대문입니다.
일반적으로 가정에서는 8GB, 16GB 정도 메모리를 사용하는데, 운영체제나 다른 프로그램 때문에 실제 사욜량은 절반도 안됩니다. 이 때 그럼 8GB기준으로 겨우 4GB를 저장할 수 있는데, 이는 매우 작은 용량입니다.
또한 메모리에 저장되어 있기 때문에, 중간에 꺼져 버린다면 처음부터 다시 보내고 저장해야하는 경우도 생길 수 있습니다.
새로운 저장 방식
디스크에 바로 저장하기
기존의 방법과는 달리 파일이 오는대로 바로 바로 디스크에 저장하는 방법이 더 좋아보입니다. 일반 적으로 디스크는 256GB 부터 1TB까지 다양하게 가정에서 사용하기 때문에, 훨씬 더 큰 용량을 저장할 수 있습니다.
또한, 바로 영구적으로 저장되기 때문에, 중간에 오류가 나더라도, 곧 바로 다음 seq를 받아 저장할 수 있습니다.
RandomAccessFile 사용하기
자바의 RandomAccessFile 클래스는 파일을 읽고 쓰게 해주는 클래스입니다. 보통 GUI에 익숙해져 있는 우리는 파일은 "마우스로 클릭하고 열어서" 보거나, 수정하거나는데 익숙해져 잇습니다.
하지만, RandomAccessFile 클래스를 사용하면, 코드로 해당 파일에 대해 접근할 수 있습니다. 또한 원하는 파일 위치에 접근도 가능하기 때문에 언제든지 해당 위치에서 파일을 읽거나 쓸 수 있습니다.
파일은 어떻게 저장 되는가?
위 내용에 대한 설명을 좀 더 돕기 위해 기본적으로 파일이 어떻게 저장되는지 이해할 필요가 있습니다. 파일은 일반적으로 배열 처럼 일렬로 저장됩니다. 여기서 배열로 저장할 수도, 링크드 리스트를 쓸 수도 있겠지만, 어쨋든 일렬로 저장되는게 핵심입니다.
파일 시스템에서는 데이터를 연속된 바이트의 시퀀스로 간주하는데, 이는 결국 파일에 담긴 모든 정보는 바이트이고, 각 바이트는 고유한 오프셋(위치)을 가집니다.
파일 생성하기
디스크에 바로 저장하기
| RandomAccessFile file = new RandomAccessFile(filePath, "rw" ); |
|---|
원하는 filePath(파일 이름)에, 권한을 부여하여 파일을 생성할 수 있습니다.\\
파일 포인터 확인
디스크에 바로 저장하기
| long pointerPosition = file.getFilePointer(); |
|---|
파일이 포인터를 확인할 수 있는 메서드입니다. 파일에서 원하는 위치로 잘 이동했는지 확인할 수 있습니다.
파일 위치 이동과 쓰기
디스크에 바로 저장하기
| file.seek(0);file.write(fileBytes); |
|---|
원하는 파일의 특정 위치로 이동하려면 file.seek()메서드를 입력하면 됩니다. file.seek(0)인 경우에는 파일의 시작 위치가 되겠습니다.
이후 file.write를 사용하여 파일에 원하는 바이트를 쓰면 됩니다.
디스크에 영구적으로 저장하기
이제 파일이 들어올 때 마다 해당 파일의 seq번호를 참조하여 파일의 위치로 접근 후(seek) 데이터를 쓰는 방식으로 코드를 구현하였습니다.
| package org.example;import lombok.Data;import org.example.types.FileType;import java.io.\;import java.nio.ByteBuffer;import java.util.UUID;@Datapublic class FileSaver { private final String sender; private final String directory = "C:\\Users\\user\\Desktop\\BEmetoring\\test\\output\\"; private RandomAccessFile file; private void set(){ String filePath = generateUniqueFileName();// fileName에 해당하는 빈 파일 set하기 try { file = new RandomAccessFile(filePath, "rw" ); System.out.println("empty file maded: " +filePath); } catch (IOException e) { System.out.println("can't set new file"); } } private String generateUniqueFileName() { return directory + UUID.randomUUID(); } public void save(int seq, byte\[\] fileBytes) { long FILE\_SEGMENT\_SIZE = 10 \ 10;// seq, fileByte\[\] if (this.file == null) { System.out.println("set empty File!!"); set(); } try { file.seek(FILE\_SEGMENT\_SIZE \ seq); file.write(fileBytes); } catch (IOException e) { System.out.println("can't write file"); } } public void writeSender() {// write Sender in End try { file.seek(file.length()); String writer = " from " + sender; file.write(writer.getBytes()); file.close(); } catch (IOException e) { System.out*.println("can't write writer"); } }} |
|---|
Byte segment 크기는 송신측과 동일하개 맞추고 seq순서에 따라 하나씩 바로 바로 저장하면 메모리 저장없이 바로 디스크에 저장이 가능합니다.


