2016-08-08 1 views
0

Apache OpenNLP에서 음성 인식 태그를 사용하려면 ~ 5MB 바이너리 파일을 읽어야하는 Android 앱을 만듭니다. 필자는 ByteBuffer와 사용자 정의 ByteBufferInputStream 클래스를 사용하여 파일을 빠르게 읽을 수있는 경로를 시도했습니다. 나는 그것을 정확하게하고 있다고 생각했지만, 메소드에 의해 리턴 된 POSModel을 체크했을 때 'null'이되었다. 일어날 일은 ByteBuffer가 바이너리 파일에서 정보를 읽고 그 정보를 POSModel 생성자에 대한 InputStream으로 제공한다는 것입니다. 여기 바이너리 파일 내용을 빠르게 읽는 빠른 방법이 제대로 작동하지 않습니다.

바이너리 파일에서 음성 모델의 부분을 얻기에 대한 코드입니다 :

public POSModel setupPOSModel() { 
     ByteBufferInputStream modelIn = null; 
     POSModel model = null; 
     try { 
      InputStream stream = getResources().openRawResource(R.raw.en_pos_maxent); 
      byte[] b = IOUtils.toByteArray(stream); 
      ByteBuffer buf = ByteBuffer.wrap(b); 

      modelIn = new ByteBufferInputStream(buf); 
      model = new POSModel(modelIn); 
     } catch (IOException e) { 
      // Model loading failed, handle the error 
      e.printStackTrace(); 
     } finally { 
      if (modelIn != null) { 
       try { 
        modelIn.close(); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
      } 
     } 
//at this point 'model' is null 
     System.out.println("POS MODEL: " + model); 
     return model; 
    } 

을 그리고 여기 또 다른 스택 오버플로 질문에서 얻은 ByteBufferInputStream에 대한 코드입니다 :

import java.io.IOException; 
import java.io.InputStream; 
import java.nio.ByteBuffer; 

public class ByteBufferInputStream extends InputStream { 

    private int bbisInitPos; 
    private int bbisLimit; 
    private ByteBuffer bbisBuffer; 

    public ByteBufferInputStream(ByteBuffer buffer) { 
     this(buffer, buffer.limit() - buffer.position()); 
    } 

    public ByteBufferInputStream(ByteBuffer buffer, int limit) { 
     bbisBuffer = buffer; 
     bbisLimit = limit; 
     bbisInitPos = bbisBuffer.position(); 
    } 

    @Override 
    public int read() throws IOException { 
     if (bbisBuffer.position() - bbisInitPos > bbisLimit) 
      return -1; 
     return bbisBuffer.get(); 
    } 
} 

이제 최종 목표는 가능한 한 빨리 "en_pos_maxent"바이너리 파일을 읽는 것입니다 (현재 일반 InputStream을 사용하면 약 20 초 걸립니다). 따라서 내 원형 파일보다 파일 내용을 빨리 얻는 방법이 더 좋습니다. ByteBuffer를 사용하여 th 다른 방법으로도 작동 할 수 있습니다.

업데이트 :

다음 방법에 의해 던져진 예외 스택 추적 : 당신이 POSModel 초기화에 의해 던져진 예외에 대해 더 자세히 들어가없이

08-08 14:59:38.220 2735-3351/com.newssummary W/System.err: java.util.zip.ZipException: CRC mismatch 
08-08 14:59:38.220 2735-3351/com.newssummary W/System.err:  at java.util.zip.ZipInputStream.readAndVerifyDataDescriptor(ZipInputStream.java:215) 
08-08 14:59:38.220 2735-3351/com.newssummary W/System.err:  at java.util.zip.ZipInputStream.closeEntry(ZipInputStream.java:164) 
08-08 14:59:38.220 2735-3351/com.newssummary W/System.err:  at opennlp.tools.util.model.BaseModel.loadModel(BaseModel.java:245) 
08-08 14:59:38.220 2735-3351/com.newssummary W/System.err:  at opennlp.tools.util.model.BaseModel.<init>(BaseModel.java:179) 
08-08 14:59:38.220 2735-3351/com.newssummary W/System.err:  at opennlp.tools.postag.POSModel.<init>(POSModel.java:105) 
08-08 14:59:38.220 2735-3351/com.newssummary W/System.err:  at com.newssummary.MainActivity$override.setupPOSModel(MainActivity.java:245) 
08-08 14:59:38.220 2735-3351/com.newssummary W/System.err:  at com.newssummary.MainActivity$override.access$dispatch(MainActivity.java) 
08-08 14:59:38.220 2735-3351/com.newssummary W/System.err:  at com.newssummary.MainActivity.setupPOSModel(MainActivity.java:0) 
08-08 14:59:38.221 2735-3351/com.newssummary W/System.err:  at com.newssummary.MainActivity$4.doAsync(MainActivity.java:190) 
08-08 14:59:38.221 2735-3351/com.newssummary W/System.err:  at com.newssummary.MainActivity$4.doAsync(MainActivity.java:182) 
08-08 14:59:38.221 2735-3351/com.newssummary W/System.err:  at com.arasthel.asyncjob.AsyncJob$4.run(AsyncJob.java:91) 
08-08 14:59:38.221 2735-3351/com.newssummary W/System.err:  at java.lang.Thread.run(Thread.java:818) 
+0

'POSModel' 초기화가 IOException을 던집니까? 스택 트레이스를 공유 할 수 있습니까? – oldrinb

+0

ByteArray를 호출 할 때 이미 전체 스트림을 배열에 복사했습니다. – lionscribe

+1

'ByteBufferInputStream'과'ByteBuffer'와 바이트 배열을 없애고 원래의 스트림을'POSModel'의 생성자에 직접 넘겨줍니다. 빠르지 않으면'BufferedInputStream'으로 랩핑하십시오. 이 모든 여분의 헛소리는 시간과 공간을 낭비하고 버그를 가져 오는 것입니다. – EJP

답변

0

, 나는 단지 조금을 제안 할 수 있습니다 단순화의 여기 ByteBuffer을 완전히 피하십시오. 다음과 같이 사용을 고려 ByteArrayInputStream :

import java.io.ByteArrayInputStream; 

final byte[] data = IOUtils.toByteArray(stream); 
final InputStream memstream = new ByteArrayInputStream(data); 

model = new POSModel(memstream); 

을 달리, BufferedInputStream 사용을 고려하는 대신 직접 제 큰 버퍼에 전체 자원을 읽어.


공유 한 예외 추적은 모델 데이터에 발생하는 일부 손상이 실제 리소스 데이터 또는 측면 IOUtils.toByteArray의 효과 또는 ByteBufferInputStream 구현으로 하나, 거기에 제안합니다. ByteArrayInputStream을 사용해보고 어떻게되는지 알려주세요.

+0

도움을 주셔서 감사합니다. BufferedInputStream을 사용하지 않은 이유는 BufferedInputStream의 속도가 일반적인 InputStream의 속도와 거의 동일하기 때문입니다. – Me2

+1

@ Me2 이는 입력 스트림이 이미 버퍼링되었음을 나타냅니다. – EJP

+2

5MB의 리소스를 읽는 데는 20 초 정도 걸리지 않습니다. 당신이 갖고있는 문제는 POSModel 내부에있는 것으로 보이며, 버퍼로 무엇을 하든지 도움이되지 않습니다. – lionscribe

관련 문제