Android的:如何拥有从InputStream随机访问? [英] Android: how to have random access from an InputStream?

查看:247
本文介绍了Android的:如何拥有从InputStream随机访问?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个InputStream,相对文件名称和大小。

I have an InputStream, and the relative file name and size.

我需要访问/读取的InputStream一些随机的(增加)的位置。该位置被存储在一个整数数组(名为偏移量)。

I need to access/read some random (increasing) positions in the InputStream. This positions are stored in an integer array (named offsets).

InputStream inputStream = ...

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

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

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

Now, given an InputStream, I've found only two possible solutions to jump to random (increasing) positions of the file.

第一种是使用跳过()在的InputStream (的方法,注意,我实际使用< A HREF =htt​​p://developer.android.com/reference/java/io/BufferedInputStream.html相对=nofollow>的BufferedInputStream ,因为我需要的标记()和的复位()文件指针)。

The first one is to use the skip() method of the InputStream (note that I actually use BufferedInputStream, since I will need to mark() and reset() the file pointer).

//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次,足以确保它总会找到正确的偏移量)

The problem is that, during my tests, for some (usually big) offsets, it has cycled 5 or more times before skipping the correct number of bytes. Is it normal? And, above all, can/should I thrust skip()? (That is: Are 10 cycles enough to be SURE it will ALWAYS arrive to the correct offset?)

我发现的唯一的另一种方法是创建一个 RandomAccessFile的<一个/ A>在的InputStream 的,通过<一个href="http://developer.android.com/reference/java/io/File.html#createTempFile%28java.lang.String,%20java.lang.String,%20java.io.File%29"相对=nofollow> File.createTempFile(preFIX,后缀,目录)和下面的函数。

The only alternative way I've found is the one of creating a RandomAccessFile from the InputStream, through File.createTempFile(prefix, suffix, directory) and the following function.

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 的实际上是一个更好的解决方案,但性能是指数差(首先是因为我将有一个以上的文件)。

Having a RandomAccessFile is actually a much better solution, but the performance are exponentially worse (above all because I will have more than a single file).

编辑:使用的字节[]缓冲区=新的字节[文件大小] 的加速(和很多)的RandomAccessFile的创作

Using byte[] buffer = new byte[fileSize] speeds up (and a lot) the RandomAccessFile creation!

//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随机访问?

Now, is there a better (or more elegant) solution to have a "random" access from an InputStream?

推荐答案

这是一个有点可惜你有一个的InputStream 来开始,但在这种情况下缓冲在流文件是没有用的当且仅当你总是跳跃前进。但你不必指望的时候,你有一个名为的数量,这是不感兴趣的真的。

It's a bit unfortunate you have an InputStream to begin with, but in this situation buffering the stream in a file is of no use iff you are always skipping forward. But you don't have to count the number of times you have called skip, that's not really of interest.

您的做什么的要检查,如果流已经结束已经到prevent一个无限循环。检查<一href="http://grep$c$c.com/file/repository.grep$c$c.com/java/root/jdk/openjdk/6-b14/java/io/InputStream.java#InputStream.skip%28long%29"相对=nofollow>默认源 的实施,我会说,你必须不断的打电话,直到它返回0。这将指示流的末尾已到达。的JavaDoc有点不清楚这对我的口味。

What you do have to check if the stream has ended already, to prevent an infinite loop. Checking the source of the default skip implementation, I'd say you'll have to keep calling skip until it returns 0. This will indicate the end of stream has been reached. The JavaDoc was a bit unclear about this for my taste.

这篇关于Android的:如何拥有从InputStream随机访问?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆