在Java/Android中读取文件的一部分

5
我知道这可能是一个简单的问题,但不幸的是这是我第一次使用Java和Android SDK。
我正在使用Apache HTTP库上传文件到Android,特别是使用MultipartEntity。我要上传到一个服务,该服务允许我发送文件块,并在完成后重新组装它们。我想利用这个功能。
下面是场景:
文件FOO.BAR有20 MB大小。我将其分成任意大小的块,比如1 MB,也就是20个块。第3个和第14个块失败了(可能是移动电话/ WiFi连接不好)。现在我可以重新上传这两个块,一切都会很好。
我想知道的是如何只读取文件的一部分(例如3MB和4MB之间的数据)?
文件块应该是InputStream或File对象。
谢谢, Makoto
3个回答

4
你可以使用skip(long)方法跳过InputStream中的字节数,或者在File对象上创建RandomAccessFile并调用其seek(long)方法将指针设置到该位置,以便从那里开始读取。下面的快速测试读取一个4mb+文件(3m和4mb之间),并将读取的数据写入一个".out"文件中。
import java.io.*;
import java.util.*;

public class Test {

    public static void main(String[] args) throws Throwable {
       long threeMb = 1024 * 1024 * 3;
       File assembled =  new File(args[0]); // your downloaded and assembled file
       RandomAccessFile raf = new RandomAccessFile(assembled, "r"); // read
       raf.seek(threeMb); // set the file pointer to 3mb
       int bytesRead = 0;
       int totalRead = 0;
       int bytesToRead = 1024 * 1024; // 1MB (between 3M and 4M

       File f = new File(args[0] + ".out");
       FileOutputStream out = new FileOutputStream(f);

       byte[] buffer = new byte[1024 * 128]; // 128k buffer 
       while(totalRead < bytesToRead) { // go on reading while total bytes read is
                                        // less than 1mb
         bytesRead = raf.read(buffer);
         totalRead += bytesRead;
         out.write(buffer, 0, bytesRead);
         System.out.println((totalRead / 1024));
       }
    }
}

谢谢提到RandomAccessFile。这将会很有帮助。 - Makotosan
raf应该像“try(RandomAccessFile raf = new RandomAccessFile(new File(..”一样关闭。 - Yura

1

我终于搞定了...只是需要发现有一个ByteArrayInputStream可以让我将我的byte[]缓冲区转换为InputStream。从这里开始,我现在可以跟踪哪些块失败并处理它。感谢Konstantin提供的帮助。以下是我的实现:

    final int chunkSize = 512 * 1024; // 512 kB
    final long pieces = file.length() / chunkSize;
    int chunkId = 0;

    HttpPost request = new HttpPost(endpoint);

    BufferedInputStream stream = new BufferedInputStream(new FileInputStream(file));

    for (chunkId = 0; chunkId < pieces; chunkId++) {
        byte[] buffer = new byte[chunkSize];

        stream.skip(chunkId * chunkSize);
        stream.read(buffer);

        MultipartEntity entity = new MultipartEntity();
        entity.addPart("chunk_id", new StringBody(String.valueOf(chunkId)));
        request.setEntity(entity);
        ByteArrayInputStream arrayStream = new ByteArrayInputStream(buffer);

        entity.addPart("file_data", new InputStreamBody(arrayStream, filename));

        HttpClient client = app.getHttpClient();
        client.execute(request);
    }

1
使用 FileInputStream 流的 skip() 方法来定位到所需的片段。

那会告诉它从哪里开始……但我怎么才能让它只读取1 MB的数据而不再继续读取呢? - Makotosan
好的,那就是你在读取字节。计算一下你已经读了多少,并在读取1MB后停止。 - Konstantin Burov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接