2013-04-29 82 views
3

我正在单独从网上下载文件。像3个地区一样。可以说我必须下载一个大小为1024kB的文件,并且我已经将该区域设置为0-340kB,341-680kB和681kB-1024kB。我有单独的每个部分的线程。但是,我现在的问题是,将下载的文件内容写入单个文件。写下载文件的部分区域

由于我们有3个线程,每个线程都会按顺序下载需要写入文件的部分。

我该如何做到这一点?我想到有3个临时文件并写入它们。一旦所有文件写入,我必须逐个文件读取并写入一个文件。我觉得这是一种开销。还有其他更好的方法吗?

在此先感谢。

+0

我不确定这个,所以我把它作为评论发布,但是你不能在文件中的指定位置写入吗?既然你知道每个部分的大小,我认为你可以创建一个1024kB的空白文件,并且每个线程都可以从一个不同的索引开始写。 – DeadlyJesus 2013-04-29 12:44:36

+0

为什么有人希望有三个线程来下载文件并大幅增加开销? – 2013-04-29 12:50:12

+0

实际上,我想通过将文件分割成多个部分并分别下载它们来提高文件下载速度,从而提高整体速度。这是我想要实现的逻辑背后的想法 – Dinesh 2013-04-29 14:18:13

回答

0

要清楚,我不相信这种方法实际上会提高下载速度。不过,如果您从多个镜像下载相同的文件,它可能会提供更一致的下载速度。

首先,如果您的文件不是太大,您可以在写出之前缓冲所有文件。因此,分配你的所有线程可以访问一个缓冲区:

byte[] buf = new byte[fileSize]; 

现在你创建一个合适的主题类型:

public class WriterThread extends Thread 
{ 
    byte[] buf; 
    int write_pos, write_remaining; 

    public WriterThread(byte[] buf, int start, int len) 
    { 
     this.buf = buf; 
     this.write_pos = start; 
     this.write_remaining = len; 
    } 

    @Override 
    public void run() 
    { 
     try (Socket s = yourMethodForSettingUpTheSocketConnection(); 
      InputStream istream = s.getInputStream()) { 
      while (this.write_remaining > 0) { 
       int read = istream.read(this.buf, this.write_pos, this.write_remaining); 
       if (read == -1) error("Not enough data received"); 
       this.write_remaining -= read; 
       this.write_pos += read; 
      } 
      // otherwise you are done reading your chunk! 
     } 
    } 
} 

现在你可以开始为许多WriterThread对象与适当的开始和长度。例如,对于一个文件,是6000个字节大小:

byte[] buf = new byte[6000]; 
WriterThread t0 = new WriterThread(buf, 0, 3000); 
WriterThread t1 = new WriterThread(buf, 3000, 3000); 
t0.start(); 
t1.start(); 
t0.join(); 
t1.join(); 
// check for errors 

注意的重要一点在这里:每个WriterThreads都有referecence完全相同的缓冲,只是不同的偏移,它开始于写作。当然,你必须确保yourMethodForSettingUpTheSocketConnection请求从偏移量this.write_pos开始的数据;你如何做到这一点取决于你使用的网络协议,超出了你所问的范围。

如果您的文件太大而无法放入内存,则此方法无效。相反,您必须先使用(较慢)方法首先创建一个大文件,然后写入该文件。虽然我还没有尝试过,你应该能够使用java.nio.file.File.newByteChannel()' to set up a suitable SeekableByteChannel as your output file. If you create such a SeekableByteChannel sbc`,那么你应该能够做到

sbc.location(fileSize - 1); // move to the specified position in the file 
sbc.write(java.nio.ByteBuffer.allocate(1)); // grow the file to the expected final size 

然后用每个线程一个不同SeekableByteChannel对象,指向同一个文件在磁盘上,并使用SeekableByteChannel.location(int)方法设置写入起始位置。你需要一个临时byte[]围绕你可以用一个ByteBuffer(通过ByteBuffer.wrap()),但在其他方面的战略是类似于上面:

thread_local_sbc.location(this.write_pos); 

,然后每thread_local_sbc.write()将会写入文件开始this.write_pos