# mark
/** * 특정 시점을 기록하는 메소드 : mark * readlimit은 마킹할 위치를 기록하는 것이 아니라,
* 현재 위치를 마킹하고나서 최대 몇개의 byte를 더 읽을 수 있는지를 의미한다
* * 예를 들어, readlimit을 100으로 설정했다면,
* 지금 mark를 호출하고 read()를 101번 호출 할 수 없는 것이다. */
# reset
/** * mark되어 있는 지점으로 돌아간다 *
이 이후에 read를 하면 아까 mark 해두었던 시점부터 데이터를 읽어들이는 것이다.
*/
# public boolean markSupported()
/**
* 이 bufferReader, inputStream, 입력 스트림 등 구현체가 mark / reset을 지원하는지, 지원하지 않는지를 표기한다.
*/
# mark 하는 이유
BufferedReader는 휘발성 메모리이기 때문에 검사를 위해서 한번 읽고나면, 이후의 처리가 불가능하다.
예를 들어, readLine으로 읽어 검사한 후 json이라서 objectmapper의 readValue로 다시 처리를 하려고 하면 readLine으로 읽으면서 메모리가 날아갔기 때문에 readValue를 하려는 데이터는 이미 null인 상태인 것이다.
그래서 처음 생각한 것은, 따로 복사를 해두는 방법이었다.
그러나 BufferedReader br2 = bufferedReader; 와 같이 새로운 변수에 할당해봤자 얕은 복사로 같은 메모리를 가리키기 때문에 다시 쓸 수 없다. 그러면 깊은 복사를 어떻게 할 수 있을까? 찾아보니 방법을 쉽게 찾을 수 없었다.
BufferedReader는 mark와 reset이라는 기능을 제공하고 있었다.
이것이 무엇이냐면, RDBMS의 Savepoint와 Rollback과 유사한 기능이라고 볼 수 있다.
BufferedReader에서 mark를 해두면 reset으로 해당 마크 지점으로 되돌아갈 수 있다.
mark와 reset의 사양에 대해 간단히 알아보자면,
- mark는 parameter로 Integer 타입의 readAheadlimit 데이터를 받는다.
- reset은 parameter를 받지 않는다.
즉, mark로 받아올 데이터의 크기를 지정하기만 하면 reset으로 처음부터 다시 읽어올 수 있다.
구글링에서는 Integer.MAX_VALUE 로 크기를 지정했지만, 너무 커서 에러가 발생하는 경우가 있다.
그래서 구현한 코드는 다음과 같다.
public static JSONObject parseJSON(BufferedReader bufferedReader) {
JSONObject jObj = new JSONObject();
ObjectMapper mapper = new ObjectMapper();
int BUFF_SIZE = 262144;
try {
String inputLine;
bufferedReader.mark(BUFF_SIZE);
//readLine으로 '<' 확인 후, 있을 시 초기화된 JSONObject를 그대로 반환
while((inputLine = bufferedReader.readLine()) != null) {
if(inputLine.indexOf("<") != -1) return jObj;
}
//검사를 통과하면 JSONObject로 간주하고 reset => API 사양/필요에 따라 추가 처리
bufferedReader.reset();
jObj = mapper.readValue(bufferedReader, JSONObject.class);
} catch (Exception e) {
e.printStackTrace();
} finally{
try {
bufferedReader.close();
} catch(Exception e) {
e.printStackTrace();
}
}
return jObj;
}
위와 같이 구현하면, BufferedReader 데이터를 다시 읽어서 HTML 데이터를 예외처리하고 JSONObject만을 읽어낼 수 있다!
이 때, 상황에 맞게 (1)BUFF_SIZE 크기 와 (2)indexOf로 검사할 문자(<) 만 신경써주면 된다.
출처 :
https://devlifetestcase.tistory.com/50
[Java] BufferedReader 다시 읽는 방법 (feat.mark, reset 사용법)
프로젝트 진행 중에 외부 API 데이터를 끌어와 json 형태로 보여주는 기능을 구현해야 했다. 기능 자체는 이미 API에서 제공하고 있기에 금방 구현했지만, 간헐적으로 에러가 콘솔창에 찍혔다. < 구
devlifetestcase.tistory.com
'개발 > JAVA' 카테고리의 다른 글
[Intellij] 실행 가능한 jar파일 만들기 (0) | 2022.12.23 |
---|---|
[Jackson] ObjectMapper serialize, deserialize (2) | 2022.12.16 |
[JAVA] inputStream, InputStreamReader, bufferReader/Writer 총정리 (0) | 2022.12.13 |
[JAVA] new BufferedReader(new InputStreamReader(conn.getInputStream())); (0) | 2022.12.13 |
[Java] URLConnection 과 HttpURLConnection 클래스 사용법 (0) | 2022.12.08 |