【问题标题】:Getting a portion of file as byte[] at a time一次获取文件的一部分作为 byte[]
【发布时间】:2013-09-21 00:20:21
【问题描述】:

我正在尝试一次处理 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 long 变量让我跳过了 1048576 个字节,我想通过调用 readFile(file, 1048576) 接收到的第二个 10MB 与来自的第一个字节数组相同前 10MB。因此它并没有真正跳过前 10MB。

这里有什么问题?有没有其他方法可以实现这个想法?

【问题讨论】:

  • 您不会以相同的数量增加偏移量,因此下一个偏移量将是 2x 1048576。因此您始终获得相同的字节。
  • 我正确地偏移了它,2x 1048576 将是第三个块,因为第一个块的偏移量为 0 对吗?
  • 所以您一遍又一遍地阅读File 并从方法外部增加offset 变量?你能添加调用你的方法的代码吗?

标签: java android file stream bytearray


【解决方案1】:

重新设计方法。目前,您正在复制字节数组,就像它过时一样:一次从缓冲区到 ByteArrayOutoutStream,然后再从那里复制到返回值。因此,您一次需要其中三个。更改方法的签名,以便 调用者 提供字节数组以及偏移量和流,并让它返回计数。换句话说,完全摆脱它,只需从您调用它的任何地方调用 FileInputStream.read(buffer, offset, length)。

【讨论】:

  • 这个问题以及我选择使用输入和输出缓冲区的原因是,如果说最后一个块是 5MB,我用长度 = 10MB 调用FileInputStream.read(buffer, offset, length),那么不会最后一个块返回一个只有 5MB 数据的 10MB 字节数组?这会影响将文件转换为 json 并通过 http 上传吗?
  • 是的,这就是为什么 read() 返回一个长度,这就是为什么 Java 充满了带有签名的方法 (byte[], offset, length);
【解决方案2】:

因此,根据用户@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 时,我必须制作字节数组的新副本。应该有一种更有效的方法,但目前这对我来说很好。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-14
    • 1970-01-01
    • 1970-01-01
    • 2022-12-01
    相关资源
    最近更新 更多