2016-02-17 15 views
10

Próbuję pobrać plik pdf za pomocą URLConnection. Oto, jak skonfigurować obiekt połączenia.Plik PDF do pobrania za pomocą BlockingQueue

URL serverUrl = new URL(url); 
urlConnection = (HttpURLConnection) serverUrl.openConnection(); 
urlConnection.setDoInput(true); 
urlConnection.setRequestMethod("GET"); 
urlConnection.setRequestProperty("Content-Type", "application/pdf"); 
urlConnection.setRequestProperty("ENCTYPE", "multipart/form-data"); 
String contentLength = urlConnection.getHeaderField("Content-Length"); 

Otrzymałem dane wejściowe z obiektu połączenia.

bufferedInputStream = new BufferedInputStream(urlConnection.getInputStream()); 

I strumień wyjściowy do zapisu zawartości pliku.

File dir = new File(context.getFilesDir(), mFolder); 
if(!dir.exists()) dir.mkdir(); 
final File f = new File(dir, String.valueOf(documentName)); 
f.createNewFile(); 
final BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(f, true)); //true for appendMode 

BlockingQueue jest tworzony tak, aby wątki wykonujące operacje odczytu i zapisu mogły uzyskać dostęp do kolejki.

final BlockingQueue<ByteArrayWrapper> blockingQueue = new ArrayBlockingQueue<ByteArrayWrapper>(MAX_VALUE,true); 
final byte[] dataBuffer = new byte[MAX_VALUE]; 

Utworzony wątek do odczytu danych z InputStream.

Thread readerThread = new Thread(new Runnable() { 
     @Override 
     public void run() { 
     try { 
      int count = 0; 
      while((count = bufferedInputStream.read(dataBuffer, 0, dataBuffer.length)) != -1) { 
       ByteArrayWrapper byteArrayWrapper = new ByteArrayWrapper(dataBuffer); 
       byteArrayWrapper.setBytesReadCount(count); 
       blockingQueue.put(byteArrayWrapper); 
      } 
      blockingQueue.put(null); //end of file 
      } catch(Exception e) { 
       e.printStackTrace(); 
      } finally { 
       try { 
       bufferedInputStream.close(); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
      } 
     } 
}); 

Teraz wątek pisarza odczytuje zawartość tego pliku.

Thread writerThread = new Thread(new Runnable() { 
     @Override 
     public void run() { 
     try { 
      while(true) { 
       ByteArrayWrapper byteWrapper = blockingQueue.take(); 
       if(null == byteWrapper) break; 
       bufferedOutputStream.write(byteWrapper.getBytesRead(), 0, byteWrapper.getBytesReadCount()); 
      } 
      bufferedOutputStream.flush(); 
     } catch(Exception e) { 
       e.printStackTrace(); 
     } finally { 
       try { 
       bufferedOutputStream.close(); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
     } 
     } 
}); 

Wreszcie wątki są uruchamiane.

readerThread.start(); 
writerThread.start(); 

Teoretycznie powinien odczytać plik z InputStream i zapisać go w pliku docelowym. W rzeczywistości jednak tworzy pusty plik PDF. W innym momencie pokazuje nieprawidłowy wyjątek w formacie PDF. Rozmiar pliku jest zgodny z długością treści obiektu InputStream. Czy jest coś, czego mi brakuje?

Odpowiedz

5

Nie jestem zaznajomiony z ByteArrayWrapper. Czy po prostu zawiera odniesienie do tablicy?

public class ByteArrayBuffer { 
    final private byte[] data; 

    public ByteArrayBuffer(byte[] data) { 
     this.data = data; 
    } 

    public byte[] getBytesRead() { 
     return data; 
    } 

    /*...etc...*/ 
} 

Jeśli tak. to byłby problem: wszystkie obiekty ByteArrayWrapper są wspierane przez tę samą macierz. Które jest wielokrotnie nadpisywane przez autora. Chociaż BlockingQueue wykonał ciężką pracę polegającą na bezpiecznym publikowaniu każdego obiektu z jednego wątku na drugi.

Najprostszą poprawką może być niezmienna wersja ByteArrayWrapper, tzn. Nie należy jej zmieniać po opublikowaniu w innym wątku. Biorąc kopię tablicy na budowie będzie najprostszy:

public ByteArrayWrapper(byte[] data) { 
    this.data = Arrays.copyOf(data, data.length); 
} 

Innym problemem jest to, że „BlockingQueue nie akceptuje elementy null” (patrz BlockingQueue docs), a więc „koniec wejścia” wartość wartownik nie praca. Wymiana null z

private static ByteArrayWrapper END = new ByteArrayWrapper(new byte[]{}); 

w odpowiednich miejscach będzie naprawić.

Dokonując tych zmian w kopii kodu, udało mi się odzyskać wierną kopię pliku PDF.

+0

Tak, tak.Masz rację https://android.googlesource.com/platform/packages/inputmethods/LatinIME/+/03118a2/java/src/com/android/inputmethod/latin/ByteArrayWrapper.java – xAF

Powiązane problemy