2017-04-07 2 views
1

내 응용 프로그램에는 별도의 스레드가 있으며, 매분마다 ScheduledExecutorService.scheduleAtFixedRate()에 의해 실행되며 여러 웹 사이트의 rss 피드를 구문 분석합니다. 나는 XML을 받기 위해 아파치 HttpClient를 사용하고있다.때때로 BufferedReader.readLine()가 응답하지 않음

샘플 코드 :

InputStream inputStream = HTTPClient.get(url);  
String xml = inputStreamToString(inputStream, encoding, websiteName); 

public static String inputStreamToString(InputStream inputStream, String encoding, String websiteName) 
{ 

    BufferedReader bufferedReader = null; 
    PrintWriter printWriter = null; 
    StringBuilder stringBuilder = new StringBuilder(); 

    int letter; 
    try 
    { 
     bufferedReader = new BufferedReader(new InputStreamReader(inputStream, encoding)); 
     printWriter = new PrintWriter(new File("src/doclog/" 
       + websiteName + "_" 
       + new SimpleDateFormat("MM_dd_yyyy_hh_mm_ss").format(new Date(System.currentTimeMillis())) 
       + "_" + encoding + ".txt"), encoding); 
     while((letter = bufferedReader.read()) != -1) 
     { 
      char character = (char) letter; 
      printWriter.print(character);    
      stringBuilder.append(character); 
     } 
    } 
    catch(IOException e) 
    { 
     throw new RuntimeException(e); 
    } 
    finally 
    { 
     try 
     { 
      if(bufferedReader != null) 
      { 
       bufferedReader.close(); 
      } 
      if(printWriter != null) 
      { 
       printWriter.close(); 
      } 
     } 
     catch(IOException e) 
     { 
      e.printStackTrace(); 
     } 
    } 
    System.out.println("String built"); 
    return stringBuilder.toString(); 
} 

그리고 HttpClient를 클래스 : 제목 말한다

public class HTTPClient 
{ 
    private static final HttpClient CLIENT = HttpClientBuilder.create().build(); 

    public static InputStream get(String url) 
    {  
     try 
     { 
      HttpGet request = new HttpGet(url); 
      HttpResponse response = CLIENT.execute(request); 
      System.out.println("Response Code: " + response.getStatusLine().toString()); 
      return response.getEntity().getContent(); 
     } 
     catch(IOException | IllegalArgumentException e) 
     { 
      throw new RuntimeException(e); 
     } 
    } 
} 

으로, 때로는 bufferedReader.readLine() 영원히 중단됩니다있는 기회가있다. 나는이 주제에 대한 또 다른 해답을 보았고 bufferedReader.ready()true을 반환하는지 확인하도록 제안했다. 문제는 웹 사이트가 항상 을 bufferedReader.ready()에 반환하면서 처리하는 동안 웹 사이트가 제대로 파싱된다는 것입니다.

내 스레드가 bufferedReader.readLine()에서 정지하지 않도록하려면 어떻게해야합니까? 이 중요한 경우

, response.getStatusLine().toString() 항상 편집

HTTP/1.1 200 OK

반환 난 그냥 걸림이 발생하면 bufferedReader.ready()true 실제로는 것을 발견했다.

EDIT 2

BufferedReader.read()도 건다. 하나의 웹 사이트를 다룰 때에 만 hang이 발생한다는 것은 이상한 일이며, 그 발생은 절대적으로 무작위입니다. 응용 프로그램은 15 시간 동안 작동하거나 수백 가지의 문제없는 응답을 받거나 실행 후 10 분 만에 응답 할 수 있습니다. 모든 단일 업데이트의 모든 문자를 별도의 파일에 기록하기 시작했으며 실제로 특별한 일이 없음을 알았습니다. Xml 독서는 문서 중간에 영원히 멈추고 마지막 문자는 <p dir="ltr"&g입니다. 코드를 업데이트했습니다.

또한 ScheduledExecutorService.scheduleAtFixedRate() 실행 파일의 최상위 레벨에서 Throwable을 catch하고 stackTrace를 인쇄하기 때문에 처리되지 않은 예외는있을 수 없다는 점은 주목할 만하다.

답변

1

ready() 메서드는 읽을 수있는 문자가 있음을 알리는 true을 반환합니다. 문제는 readLine()이 입력에서 줄의 끝을 찾을 때까지 차단한다는 것입니다.

공공 문자열 내의 readLine()이 는 IOException이이

이 한 줄의 텍스트를 읽어냅니다. 한 줄은 줄 바꿈 ('\ n'), 캐리지 리턴 ('\ r') 또는 캐리지 리턴 중 임의의 하나로 끝나는 것으로 간주되며 바로 뒤에 줄 바꿈이옵니다. 당신이 스트림에서 읽는 것처럼

데이터 라인의 경계 그래서 readLine() 호출 블록에 올 것이라는 보장은 없습니다.

차단하지 않는 read 방법을 사용할 수 있지만 직접 EOL을 확인해야합니다.

공개 INT 판독

배열의 일부에 문자를 읽어 IOException이 발생

(CHAR [] cbuf는 INT 렌 오프 INT)를.

이 메서드는 해당하는 read 클래스 Reader 클래스 메서드를 구현합니다. 편의상, 은 기본 스트림의 read 메서드를 반복적으로 호출하여 가능한 한 많은 문자를 읽으려고 시도합니다. 다음 조건 중 하나에 해당 될 때까지 읽어 반복은 계속된다 :

The specified number of characters have been read, 
The read method of the underlying stream returns -1, indicating end-of-file, or 
The ready method of the underlying stream returns false, indicating that further input requests would block. 

기본이되는 스트림 -1을 반환의 첫 번째 읽기 이 파일의 마지막에이 메소드가 리턴 표시하는 경우 -1. 그렇지 않은 경우,이 메소드는 실제로 읽힌 문자 수인 을 리턴합니다.

또한 읽은 문자로 줄을 다시 만들어야합니다. 한 번에 전체 라인을 읽는 것이 편리하지는 않지만 그것이 완료되어야하는 방법입니다.

+0

인코딩에 문제가 있습니까? 따라서'readLine()'은 EOL을 인식하지 못합니다. – DaSH

+0

@DaSH 나는 그렇게 생각하지 않는다. EOL이 표준입니다. readLine이 EOL을 인식하지 못하면 영원히 계속 읽게 될 것이고 라인 변수가 많은 메모리를 사용하게 될 것이므로 문자열에 쓰레기로 끝날 것입니다. – whbogado

+0

코드를 'while ((letter = bufferedReader.read())! = -1)'로 바 꾸었습니다. 이제 제대로 작동하는 것 같습니다. 고맙게도 필자는 라인을 구분할 필요가 없다. – DaSH