我试图一次处理10MB字节数组的大文件。 我试图一次获取一个字节数组(不是获取大文件的整个字节数组并拆分字节数组,所有问题都是由于内存造成的)
这是我到目前为止所做的:
private byte[] readFile(File file, int offset) throws IOException
{
BufferedInputStream inStream = null;
ByteArrayOutputStream outStream = null;
byte[] buf = new byte[1048576];
int read = 0;
try
{
inStream = new BufferedInputStream(new FileInputStream(file));
outStream = new ByteArrayOutputStream();
long skipped = inStream.skip(offset);
read = inStream.read(buf);
if (read != -1)
{
outStream.write(buf, 0, read);
return outStream.toByteArray();
}
}
finally
{
if (inStream != null) {try {inStream.close();} catch (IOException e) {}}
if (outStream != null) {try {outStream.close();} catch (IOException e) {}}
}
return null;
参数offset
也将以10MB为增量。
所以我遇到的问题是,即使skipped
长变量给我跳过了1048576个字节,我想从调用readFile(file, 1048576)
接收的第二个10MB是与前10MB的第一个字节数组相同。因此,它根本没有超过前10MB。
这里的问题是什么?还有另一种实现这个想法的方法吗?
答案 0 :(得分:1)
重新设计方法。目前你正在复制字节数组,就像它的样式一样:一次从缓冲区到ByteArrayOutoutStream,再从那里再到返回值。所以你需要同时使用其中的三个。更改方法的签名,以便调用者提供字节数组以及偏移量和流,并让它返回计数。换句话说,完全摆脱它,只需从你调用它的地方调用FileInputStream.read(buffer,offset,length)。
答案 1 :(得分:0)
因此,根据用户@EJP,我修改了代码以便有效地工作。我不再复制到ByteArrayOutputStream
因为我意识到.toByteArray
实际上返回了读取字节数组的副本并且内存效率非常低。我也只打开一次流,因此不需要跳过。
int fileLength = (int) file.length();
byte[] buffer = new byte[fileLength < FILE_UPLOAD_CHUNK_SIZE ?
fileLength : FILE_UPLOAD_CHUNK_SIZE];
int bytesRead;
int readTotal = 0;
BufferedInputStream inStream = null;
try
{
inStream = new BufferedInputStream(new FileInputStream(file));
do
{
bytesRead = inStream.read(buffer, 0, buffer.length);
if (bytesRead == -1)
{
continue;
}
byte[] finalBuffer;
if (buffer.length > bytesRead)
{
finalBuffer = Arrays.copyOf(buffer, bytesRead);
}
else
{
finalBuffer = buffer;
}
uploadChunk(
finalBuffer,
mimeType,
uploadPath,
fileLength,
readTotal,
readTotal + bytesRead - 1);
readTotal += bytesRead;
} while (bytesRead != -1);
}
finally
{
if (inStream != null)
{
inStream.close();
}
}
我对此代码的唯一缺陷是当最后一个块小于10MB时我必须创建字节数组的新副本。应该有一种更有效的方法,但这对我来说现在很好。