1

필자는 InputStream과 상대적인 파일 이름과 크기를 가지고 있습니다.Android : InputStream에서 임의 액세스하는 방법?

InputStream에서 임의의 (증가하는) 위치에 액세스하거나 읽어야합니다. 이 위치는 정수 배열 (offsets)에 저장됩니다.

InputStream inputStream = ... 

String fileName = ... 
int fileSize = (int) ... 

int[] offsets = new int[]{...}; // the random (increasing) offsets array 

이제 InputStream이 주어지면 파일 위치를 임의로 (증가하는) 점프로 이동할 수있는 두 가지 해결책을 찾았습니다.

첫 번째는 InputStream (나는 mark()reset() 파일 포인터에 필요하기 때문에 실제로, BufferedInputStream을 사용하여 주)의 skip() 방법을 사용하는 것입니다.

//Open a BufferInputStream: 
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream); 

byte[] bytes = new byte[1]; 

int curFilePointer = 0; 
long numBytesSkipped = 0; 
long numBytesToSkip = 0; 
int numBytesRead = 0; 

//Check the file size: 
if (fileSize < offsets[offsets.length-1]) { // the last (bigger) offset is bigger then the file size... 
    //Debug: 
    Log.d(TAG, "The file is too small!\n"); 

    return; 
} 

for (int i=0, k=0; i < offsets.length; i++, k=0) { // for each offset I have to jump... 
    try { 
     //Jump to the offset [i]: 
     while((curFilePointer < offsets[i]) && (k < 10)) { // until the correct offset is reached (at most 10 tries) 
      numBytesToSkip = offsets[i] - curFilePointer; 
      numBytesSkipped = bufferedInputStream.skip(numBytesToSkip); 

      curFilePointer += numBytesSkipped; // move the file pointer forward 

      //Debug: 
      Log.d(TAG, "FP: " + curFilePointer + "\n"); 

      k++; 
     } 

     if (curFilePointer != offsets[i]) { // it did NOT jump properly... (what's going on?!) 
      //Debug: 
      Log.d(TAG, "InputStream.skip() DID NOT JUMP PROPERLY!!!\n"); 

      break; 
     } 

     //Read the content of the file at the offset [i]: 
     numBytesRead = bufferedInputStream.read(bytes, 0, bytes.length); 
     curFilePointer += numBytesRead; // move the file pointer forward 

     //Debug: 
     Log.d(TAG, "READ [" + curFilePointer + "]: " + bytes[0] + "\n"); 
    } 
    catch (IOException e) { 
     e.printStackTrace(); 

     break; 
    } 
    catch (IndexOutOfBoundsException e) { 
     e.printStackTrace(); 

     break; 
    } 
} 

//Close the BufferInputStream: 
bufferedInputStream.close() 

문제는 내 테스트 중 일부 (보통 큰) 오프셋, 그것은 정확한 바이트 수를 건너 뛰는 전에 5 번 이상을 순환하고있다,는 것이다. 정상입니까? 그리고 무엇보다도, 나는 밀어 넣을 수 있습니까? 건너 뛰기()? (즉 : 충분히 10 사이클이 좌표가 항상 올바른에 도착해야하는?)

내가 찾은 유일한 다른 방법이 File.createTempFile(prefix, suffix, directory)과를 통해 의 InputStream에서 RandomAccessFile을 만드는 중 하나입니다 다음 기능. RandomAccessFile에를 갖는

public static RandomAccessFile toRandomAccessFile(InputStream inputStream, File tempFile, int fileSize) throws IOException { 
    RandomAccessFile randomAccessFile = new RandomAccessFile(tempFile, "rw"); 

    byte[] buffer = new byte[fileSize]; 
    int numBytesRead = 0; 

    while ((numBytesRead = inputStream.read(buffer)) != -1) { 
     randomAccessFile.write(buffer, 0, numBytesRead); 
    } 

    randomAccessFile.seek(0); 

    return randomAccessFile; 
} 

실제로 훨씬 더 나은 솔루션,하지만 (나는 하나의 파일보다 더 많이 가지고 있기 때문에 모든 이상) 성능이 기하 급수적으로 더 나쁘다.


EDIT :가 RandomAccessFile의 생성을 바이트 [완충액 = 새로운 바이트 [이는 파일 크기] 속도를 사용하여 (및 많은)! 이제


//Create a temporary RandomAccessFile: 
File tempFile = File.createTempFile(fileName, null, context.getCacheDir()); 
RandomAccessFile randomAccessFile = toRandomAccessFile(inputStream, tempFile, fileSize); 

byte[] bytes = new byte[1]; 
int numBytesRead = 0; 

//Check the file size: 
if (fileSize < offsets[offsets.length-1]) { // the last (bigger) offset is bigger then the file size... 
    //Debug: 
    Log.d(TAG, "The file is too small!\n"); 

    return; 
} 

for (int i=0, k=0; i < offsets.length; i++, k=0) { // for each offset I have to jump... 
    try { 
     //Jump to the offset [i]: 
     randomAccessFile.seek(offsets[i]); 

     //Read the content of the file at the offset [i]: 
     numBytesRead = randomAccessFile.read(bytes, 0, bytes.length); 

     //Debug: 
     Log.d(TAG, "READ [" + (randomAccessFile.getFilePointer()-4) + "]: " + bytes[0] + "\n"); 
    } 
    catch (IOException e) { 
     e.printStackTrace(); 

     break; 
    } 
    catch (IndexOutOfBoundsException e) { 
     e.printStackTrace(); 

     break; 
    } 
} 

//Delete the temporary RandomAccessFile: 
randomAccessFile.close(); 
tempFile.delete(); 

, InputStream로부터 「랜덤 "액세스 할 수있는 더 나은 (또는 더 우아한) 솔루션은 무엇입니까?

+0

오라클 설명서에 따르면 skip() 메소드를 신뢰해야하는지 아닌지에 대한 나의 첫 번째 질문과 관련하여 "skip 메소드는 여러 가지 이유로 작은 바이트 수를 건너 뛸 수 있습니다. 0 일 가능성이 있습니다.이는 여러 가지 조건 중 하나로 인해 발생할 수 있습니다. n 바이트를 건너 뛰기 전에 파일 끝으로 도달하는 것은 하나의 가능성에 불과합니다. " 링크 : http://docs.oracle.com/javase/7/docs/api/java/io/InputStream.html#skip%28long%29 ? ZipFile.getInputStream() –

+0

파일 (이것은 I/O 액세스를 줄일 것입니다 ...) – pskink

+0

으로부터의 InputStream을받을 수 있나요 –

답변

1

처음에는 InputStream이 약간 불행하지만이 상황에서는 파일에서 스트림을 버퍼링하면 항상 앞으로 건너 뜁니다. 그러나 당신이 skip이라고 불린 횟수를 세지 않아도됩니다. 이것은별로 관심이 없습니다.

무엇을 합니까?은 무한 루프를 방지하기 위해 스트림이 이미 종료되었는지 확인해야합니다. 기본 skip 구현의 source을 확인하면 0을 반환 할 때까지 skip을 계속 호출해야 할 것이라고 말하고 싶습니다. 이는 스트림의 끝에 도달했음을 나타냅니다. JavaDoc은 내 취향에 대해이 점에 대해 약간 명확하지 않았습니다.

+0

내가 말했듯이, 어느 시점에서 나는 마크를하고 리셋해야만한다. 즉, 나는 앞으로 나아갈 필요가있다. 내가 (표준의 InputStream이 기능을 제공하지 않음) BufferedInputStream을 사용했습니다. 가) (생략의 수를 계산에 관해서는, 나는 성능 문제. (각 오프셋)의를 시작하기 전에, 내가 가장 큰 있는지 확인 그렇게 offset은 파일 크기보다 작습니다 (보다 작음). 따라서 이론 상으로는 EoF에 대한 걱정없이 원하는만큼 건너 뛸 수 있습니다. 그러나, 나의 솔직한 의견으로는, 너무 많은 건너 뛰기()를하지 못하게하는 것이 모두 좋고 좋은 것입니다 ... –

-1

수 없습니다. InputStream는 스트림, 즉 순차 구성입니다. 귀하의 질문은 모순을 구체화합니다.

+0

실제로는 마지막 질문을 읽어야합니다 ("임의 접근"이라는 용어를 사용했습니다). 전체 질문 전체를 읽고 ... 사실, 내 질문에 당신은 이미 InputStream (내 질문에 대한 성능 문제에 대한 자세한)에서 RandomAccessFile을 만드는 방법을 찾을 수 있습니다. –