Java Android:如何从InputStream进行随机访问?

Java Android:如何从InputStream进行随机访问?,java,android,random-access,bufferedinputstream,randomaccessfile,Java,Android,Random Access,Bufferedinputstream,Randomaccessfile,我有一个InputStream,以及相对的文件名和大小 我需要访问/读取InputStream中的一些随机(递增)位置。此位置存储在整数数组中(命名偏移) 现在,给定一个InputStream,我发现只有两种可能的解决方案可以跳转到文件的随机(增加)位置 第一个是使用的方法(请注意,我实际上使用了,因为我需要使用和文件指针) 拥有一个RandomAccessFile实际上是一个更好的解决方案,但是性能会以指数级的速度下降(最重要的是因为我将拥有不止一个文件) 编辑:使用byte[]buffer

我有一个InputStream,以及相对的文件名和大小

我需要访问/读取InputStream中的一些随机(递增)位置。此位置存储在整数数组中(命名偏移)

现在,给定一个InputStream,我发现只有两种可能的解决方案可以跳转到文件的随机(增加)位置

第一个是使用的方法(请注意,我实际上使用了,因为我需要使用和文件指针)

拥有一个RandomAccessFile实际上是一个更好的解决方案,但是性能会以指数级的速度下降(最重要的是因为我将拥有不止一个文件)


编辑:使用byte[]buffer=new byte[fileSize]加快(而且大大加快)文件创建速度


//创建临时随机访问文件:
File tempFile=File.createTempFile(fileName,null,context.getCacheDir());
RandomAccessFile RandomAccessFile=toRandomAccessFile(inputStream、tempFile、fileSize);
字节[]字节=新字节[1];
int numBytesRead=0;
//检查文件大小:
如果(fileSize

现在,有没有更好(或更优雅)的解决方案可以从InputStream进行“随机”访问?

很不幸,您有一个
InputStream
开始,但是在这种情况下,如果您总是向前跳过,则在文件中缓冲流是没有用的。但是您不必计算调用
skip
的次数,这并不重要


您必须检查流是否已经结束,以防止无限循环。检查默认的
skip
实现,我认为您必须继续调用
skip
,直到它返回0。这将表明已到达流的末尾。就我的口味而言,JavaDoc对此有点不清楚。

你不能。InputStream是一个流,也就是说是一个顺序结构。您的问题在术语上存在矛盾。

好的,根据Oracle文档,关于我的第一个问题,即我是否应该信任skip()方法:由于各种原因,skip方法可能会跳过一些较小的字节数,可能是0。这可能由多种情况中的任何一种导致;在跳过n个字节之前到达文件末尾只是一种可能性。“链接:你从哪里获得InputStream?从ZIP文件:ZipFile.getInputStream()实际上,我刚刚意识到我可以使用与文件大小相同的缓冲区来加速(并且大大加快)RandomAccessFile的创建(这将减少I/O访问…)!正如我所说,在某一点上,我需要标记()并重置()位置,即我需要返回和前进。这就是为什么我使用BufferedInputStream(标准InputStream不提供此功能)。关于计算skip()的数量,我这样做是为了解决性能问题。在开始for之前(针对每个偏移量),我检查最大偏移量是否在(小于)文件大小内。因此,理论上,我可以随意跳过,而不必担心EoF。然而,老实说,我认为,防止它做太多的跳过()是很好的……实际上,只有当你读到最后一个问题(我在其中使用了“随机访问”一词)时才会这样做实际上,在我的问题中,您已经找到了从InputStream创建RandomAccessFile的方法(我的问题更多的是关于性能问题)。
InputStream inputStream = ...

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

int[] offsets = new int[]{...};  // the random (increasing) offsets array
//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() 
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;
}
//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();