2016-08-08 34 views
0

Ich erstelle eine Android-App, die eine ~ 5 mb binäre Datei lesen muss, um den Teil der Rede-Tagger von Apache OpenNLP zu verwenden. Ich versuchte eine ziemlich umständliche Route, um die Datei schnell zu lesen, mit einem ByteBuffer und einer benutzerdefinierten ByteBufferInputStream-Klasse. Ich dachte, dass ich es richtig mache, aber als ich das POSModel überprüfte, das von der Methode zurückgegeben wird, stellt es sich als "Null" heraus. Was passieren soll, ist, dass ein ByteBuffer die Informationen aus der Binärdatei liest und diese dann als InputStream dem POSModel-Konstruktor gibt.Schnelle Methode zum Lesen von binären Datei Inhalt funktioniert nicht richtig

Hier ist der Code für den Teil des Sprachmodells aus der Binärdatei bekommen:

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; 
    } 

Und hier ist der Code für die ByteBufferInputStream, die ich von einem anderen Stack-Überlauf Frage kam:

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(); 
    } 
} 

Nun, mein Endziel ist einfach, "en_pos_maxent" Binärdatei so schnell wie möglich zu lesen (derzeit, mit einem regulären InputStream, dauert es etwa 20 Sekunden), wenn es also einen besseren Weg als meine Umweg, um den Inhalt der Datei schnell zu bekommen mit einem ByteBuffer dann th bei alternativer Methode könnte auch funktionieren.

Update:

Hier ist der Stack-Trace für die nach der Methode geworfen Ausnahme:

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

wirft die 'POSModel'-Initialisierung eine' IOException'? Können Sie die Stack-Trace teilen? – oldrinb

+0

Wenn Sie toByteArray aufrufen, haben Sie bereits den gesamten Stream in ein Array kopiert. – lionscribe

+1

Löschen Sie den 'ByteBufferInputStream' und den' ByteBuffer' sowie das Byte-Array und übergeben Sie den * originalen * Stream direkt an den Konstruktor von 'POSModel'. Wenn es nicht schnell genug ist, wickle es in einen "BufferedInputStream". All diese zusätzlichen Spielereien verschwenden nur Zeit und Raum und führen Bugs ein. – EJP

Antwort

0

Ohne Sie über die Ausnahmen mehr ins Detail gehen durch die Initialisierung POSModel geworfen, kann ich nur ein bisschen vorschlagen der Vereinfachung hier zu vermeiden ByteBuffer vollständig. Betrachten wir ein ByteArrayInputStream wie folgt verwendet wird:

import java.io.ByteArrayInputStream; 

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

model = new POSModel(memstream); 

Alternativ betrachten eine BufferedInputStream anstelle von manuell die gesamte Ressource zu einem großen Puffer liest zuerst.


Die Ausnahme-Trace Sie geteilt haben schlägt einige Korruption auf die Modelldaten, entweder in den tatsächlichen Ressourcendaten oder als Nebenwirkung von IOUtils.toByteArray oder Ihre ByteBufferInputStream Implementierung auftreten gibt. Versuchen Sie es mit ByteArrayInputStream und lassen Sie uns wissen, wie es geht.

+0

Danke für die Hilfe. Der Grund, warum ich keinen BufferedInputStream verwendet habe, ist, dass die Geschwindigkeit von BufferedInputStream praktisch mit der Geschwindigkeit eines regulären InputStreams identisch ist. – Me2

+1

@ Me2 Zeigt an, dass der Eingangsstrom bereits gepuffert wurde. – EJP

+2

Das Lesen einer 5-MB-Ressource dauert nicht annähernd 20 Sekunden. Das Problem, das Sie haben, scheint in POSModel intern zu sein, und egal, was Sie mit dem Puffer tun, wird nicht helfen. – lionscribe