1

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

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

InputStream inputStream = ...

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

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

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

第一个是使用InputStream的skip()方法(请注意,我实际上使用的是BufferedInputStream,因为我需要mark()reset()文件指针)。

//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

1

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

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

于 2013-10-09T16:04:28.587 回答
-1

你不能。InputStream 是一个流,也就是说一个顺序构造。你的问题体现了一个矛盾的术语。

于 2013-10-11T08:52:19.530 回答