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