Java | Byte 배열과 바이너리 String 문자열 간의 상호 변환
소켓을 사용 중에 특정 파일을 바이너리로 변환하여 Byte 로 전송받아 사용할 경우가 있었다.
전송받은 데이터를 일반 문자열 처럼 InputStream 으로 read 한 Byte 배열을 new String(Byte[]) 로 형변환 하였다.
형변환한 String 을 getBytes() 함수를 이용하여 Byte 배열로 변환하고 ByteArrayInputStream 으로 읽어들였더니 파일이 생성되지 않았다.
전송받은 패킷을 분석해 보니 내가 전송받은 값과 처음에 Byte 배열을 String 로 형변환 하고 난 후 값이 달랐다.
그럼 String 으로 형변환 하는 곳이 문제가 있어 보였다.
어떻게 변환을 해야 하나 찾아보다 이런 아래 포스팅을 만나게 되었다.
이해하기 쉽게 설명되어 있으며 나의 시간을 단축시켜주어 매우 감사하다.
출처 : [Java] Byte 배열과 (바이너리)문자열 상호 변환하기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60 |
/**
* 바이너리 바이트 배열을 스트링으로 변환
*
* @param b
* @return
*/
public static String byteArrayToBinaryString(byte[] b) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < b.length; ++i) {
sb.append(byteToBinaryString(b[i]));
}
return sb.toString();
}
/**
* 바이너리 바이트를 스트링으로 변환
*
* @param n
* @return
*/
public static String byteToBinaryString(byte n) {
StringBuilder sb = new StringBuilder("00000000");
for (int bit = 0; bit < 8; bit++) {
if (((n >> bit) & 1) > 0) {
sb.setCharAt(7 - bit, '1');
}
}
return sb.toString();
}
/**
* 바이너리 스트링을 바이트배열로 변환
*
* @param s
* @return
*/
public static byte[] binaryStringToByteArray(String s) {
int count = s.length() / 8;
byte[] b = new byte[count];
for (int i = 1; i < count; ++i) {
String t = s.substring((i - 1) * 8, i * 8);
b[i - 1] = binaryStringToByte(t);
}
return b;
}
/**
* 바이너리 스트링을 바이트로 변환
*
* @param s
* @return
*/
public static byte binaryStringToByte(String s) {
byte ret = 0, total = 0;
for (int i = 0; i < 8; ++i) {
ret = (s.charAt(7 - i) == '1') ? (byte) (1 << i) : 0;
total = (byte) (ret | total);
}
return total;
} |
cs |
byte를 String으로 출력하기 위해, new String()으로 바로 건네주는 방법이 있지만 간혹 원하는 결과가 나오지 않아서 찾던중, Converting large byte array to binary string 라는 페이지에서 byteToBinaryString이라는 코드를 발견하고 이에 byte[]를 지원하기 위하여 추가하여 시리즈로 올린다.
byteArrayToBinaryString()에 byte[] 를 넣으면 String으로 변환, byteStringToByteArray에 String을 넣으면 byte[]를 반환하는 매우 간단한 소스이다.
참고로 이 메소드에는 비트 연산자와 시프트 연산자가 사용이 되었는데, 다음의 예를 보면서 이해하면 쉽다.
우선 n=10110101이라고 가정한다 for문에서bit가 0일때, 쉬프트 되지 않은 채로 &연산자를 만난다.
1은 byte로 표시하면 00000001이고, and연산자는 각 비트가 동일해야 1을 출력하는것이므로 첫번째 루프에서는 1이 반환되고, 이는 0보다 크므로 if문 내의 명령을 처리한다(7번째 문자를 1로 정한다.)
다음, bit가 1일 경우에는 shift연산자에 의해 한칸씩 오른쪽으로 밀리고, 가장 왼쪽에 있던 위치는 가장 왼쪽에 있었던 숫자인 1로 채운다.
즉, n>>1은 11011010이 되는것이다. 여기서 00000001과 and연산자를 하게되면 0이 출력되므로 if문의 내부는 실행되지 않는다.
이런 원리로 뒷부분부터 수정이 일어남을 확인할 수 있다.
그리고 마찬가지로 byteStringToByteArray("100010101010110")으로 입력하면 byte[]로 된 값이 반환될것이며, 원리는 위와 크게 다르지 않다.
중간에 (byte)로 캐스팅 해주긴 했는데, 특히 total=ret|total 식을 그냥 쓰면 int->byte로 변환할수 없다고 오류가 나와서 명시적 캐스팅은 해줬다. 어디서 int가 나오는지...
n>>0 |
n>>1 |
n>>2 |
n>>3 |
n>>4 |
n>>5 |
n>>6 |
n>>7 | |
n>>i |
10110101 |
11011010 |
11101101 |
11110110 |
1111011 |
1111101 |
1111110 |
11111111 |
1 |
00000001 |
00000001 |
00000001 |
00000001 |
00000001 |
00000001 |
00000001 |
00000001 |
n&1 |
1 |
0 |
1 |
0 |
1 |
1 |
0 |
1 |