/*Mission
- read() 함수로 bmp 파일의 File Size를 읽어와 fileSize int형 변수에 담는다.
- bmp 확장자의 File Size는 총 4 byte이며 3~6 byte에 저장되어 있다.
*/
주석 1
- 파일을 불러오는 FileInputStream 객체를 생성합니다.
주석 2
- 아래는 비트맵 파일의 헤더 구조입니다. Signature 부분이 2 byte를 차지하고 있습니다.
- read() 함수로 초반의 2 btye를 b 변수에 담아서 버립니다. 우리의 목적은 FileSize를 읽는 것입니다.
- read() 함수는 파일에서 1 byte씩 읽어 오는 함수인데, 끝까지 읽으면 -1을 반환해야 하기 때문에 int형으로 써야 합니다.
- 하지만...... 1 byte를 읽어 오는 데에 4 byte형 정수를 써야 한다고? 이 낭비를 해결하는 것이 오늘의 과제입니다.
주석 3
- 정수형 변수 b1, b2, b3, b4에다 1 byte씩 불러와 담습니다. FileSize 정보가 담깁니다.
주석 4
- 이 int형 변수들을 int형의 fileSize에 잘 욱여넣고 싶다!
- 애초에 read() 함수는 1 byte씩 가져올 수 있는데 4 byte 정수형에 넣는다면 이건 공간의 낭비입니다. 통신이 쉽지 않던 시절에는 더욱 그랬고, 이미 있는 공간을 활용해야 했습니다.
주석 5
- fileSize 변수에 b4, b3, b2, b1을 담습니다.
- 1 byte가 들어 있는 int형 변수 b4는 총 32 bit이며 마지막 1 byte에만 정보값이 저장된 구조입니다.
- 즉, 변수 b4를 bit로 표현하면 [][][][][][][][] [][][][][][][][] [][][][][][][][] 10110101입니다.
- 이것을 0x000000ff, 총 32 bit로 된 16진수와 교집합($, 둘 중 하나가 0이면 0)시키면 앞에 있는 3 byte는 0으로 연산되고 정보값은 그대로 나오는 현상을 보게 됩니다. f는 16진수에서 제일 큰 수 15를 담고 있습니다.
- 아래 식을 보면 이해가 쉽습니다.
0x000000ff = 0000 0000 0000 0000 0000 0000 1111 1111
b4 = [][][][][][][][] [][][][][][][][] [][][][][][][][] 10110101
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
& = 00000000 00000000 00000000 10110101
b4 & 0x000000ff에 정보값이 예쁘게 담겼습니다!
- 이것을 비트연산자<<를 사용하여 왼쪽으로 밀어 줍니다.
(b4 & 0x000000ff) << 8*3 = 10110101 00000000 00000000 00000000
- 이제 b3도 같은 연산을 하여 정보값을 왼쪽으로 8*2만큼만 밀어 줍니다.
(b3 & 0x000000ff) < 8*2 = 00000000 01010111 00000000 00000000
- b2와 b1에도 같은 연산을 하면 각각 한 자리씩을 차지하며, 이것들을 모두 더하면 32bit에 b4, b3, b2, b1이 예쁘게 담깁니다.
* b1, b2, b3, b4 순서로 불러왔지만 [b4][b3][b2][b1]로 담는 이유는?
고성능 컴퓨터 big edian에서는 최상위 바이트부터, 즉 왼쪽에서 오른쪽으로(->) 읽지만 일반 컴퓨터인 littlt endian은 최하위 바이트부터, 즉 오른쪽에서 왼쪽으로(<-) 읽기 때문에 일어나는 현상이다. little endian은 [b4][b3][b2][b1]을 b1부터 읽는다.
16진수: 0x를 숫자 앞에 붙여서 표현; 4비트
8진수: 0을 숫자 앞에 붙여서 표현; 3비트
2진수: 0b를 숫자 앞에 붙여서 표현; 1비트
주석 6
- Integer 형식을 Binary(이진수) 형식으로 변환해 주는 함수로 각각의 값을 출력합니다.
- fileSize를 출력하고 불러온 파일의 용량과 같은지 확인합니다.
- fis 객체를 닫아 파일을 닫아 줍니다.
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class program {
public static void main(String[] args) throws IOException {
// 1. 이미지 파일을 읽기 위한 파일입력스트림을 fis로 생성해 주시오.
FileInputStream fis = new FileInputStream("res/img.bmp");
// 2. read() 함수: 1바이트씩 정수형으로 읽어오는 것, 끝까지 읽으면 -1을 반환해야 하기 때문에 int형으로 불러옴
// 초반 2 바이트를 버리는 이유? signiture
int b;
b = fis.read();
b = fis.read();
// 3. fileSize 읽어 오기
int b1 = fis.read();
int b2 = fis.read();
int b3 = fis.read();
int b4 = fis.read();
// 4. fileSize에 그대로 대입하면 덮어쓰기가 된다. [b1][b2][b3][b4]로 만들려면 어떻게 해야 할까?
int fileSize = 0;
fileSize = b1; // [][][][b1];
fileSize = b2; // [][][][b2];
fileSize = b3; // [][][][b3];
fileSize = b4; // [][][][b4];
// 5. b4&0x000000ff=[][][][b4]
// 비트연산자 <<를 사용하여 왼쪽으로 밀어 준다
// [b4][b3][b2][b1]순서로 불러와야 함
fileSize =
(b4 & 0x000000ff) << 8 * 3 | // [b4][][][]
(b3 & 0x000000ff) << 8 * 2 | // [b4][b3][][]
(b2 & 0x000000ff) << 8 * 1 | // [b4][b3][b2][]
(b1 & 0x000000ff);
// 6. 출력
System.out.println(Integer.toBinaryString(b4));
System.out.println(Integer.toBinaryString(b3));
System.out.println(Integer.toBinaryString(b2));
System.out.println(Integer.toBinaryString(b1));
System.out.printf("fileSize: %d\n", fileSize);
fis.close();
}
}
'old' 카테고리의 다른 글
[이클립스] Mac 파일 인코딩 한글 깨짐 문제 해결 (0) | 2021.03.11 |
---|---|
[CSS ] display: flex 속성 (0) | 2021.03.10 |
[Java] 파일 입출력: FileInputStream, FileOutputStream 이용 (0) | 2021.03.04 |
[CSS] 선택자(Selectors) (0) | 2021.03.03 |
[HTML] 블록 요소 (0) | 2021.02.27 |