1

InputStream と、相対ファイル名とサイズがあります。

InputStream のランダムな (増加する) 位置にアクセス/読み取る必要があります。この位置は整数配列 (名前付きオフセット) に格納されます。

InputStream inputStream = ...

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

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

さて、InputStream が与えられた場合、ファイルのランダムな (増加する) 位置にジャンプするための可能な解決策は 2 つしか見つかりませんでした。

1 つ目は、 InputStreamのskip()メソッドを使用することです (ファイル ポインターをmark()およびreset()する必要があるため、実際にはBufferedInputStreamを使用していることに注意してください)。

//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 回以上循環したことです。それは正常ですか?そして、何よりも、skip()を突き刺すことができますか? (つまり、常に正しいオフセットに到達することを確認するには、10 サイクルで十分ですか?)

私が見つけた唯一の代替方法は、File.createTempFile (prefix, suffix, directory)と次の関数を使用して、 InputStreamから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;
}

RandomAccessFileを持つことは、実際にははるかに優れたソリューションですが、パフォーマンスは指数関数的に悪化します (何よりも、複数のファイルがあるため)。


編集: byte[] buffer = new byte[fileSize]を使用すると、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 から「ランダムな」アクセスを行うためのより良い (またはよりエレガントな) ソリューションはありますか?

4

2 に答える 2