В моей нынешней компании я делаю PoC о том, как мы можем написать утилиту для загрузки файлов. Мы должны использовать сокет программирования (TCP / IP) для загрузки файлов. Одним из требований клиента является то, что файл (который будет большого размера) должен передаваться порциями, например, если у нас есть файл размером 5 МБ, то у нас может быть 5 потоков, которые передают 1 МБ каждый. Я написал небольшое приложение, которое загружает файл. Вы можете скачать проект eclipe
от http://www.fileflyer.com/view/QM1JSC0
Краткое объяснение моих занятий
FileSender.java: Этот класс предоставляет байты файла. У него есть метод
sendBytesOfFile (long start, long end, long sequenceNo), который дает количество байтов.
import java.io.File;
import java.io.IOException;
import java.util.zip.CRC32;
import org.apache.commons.io.FileUtils;
public class FileSender {
private static final String FILE_NAME = "C:\\shared\\test.pdf";
public ByteArrayWrapper sendBytesOfFile(long start,long end, long sequenceNo){
try {
File file = new File(FILE_NAME);
byte[] fileBytes = FileUtils.readFileToByteArray(file);
System.out.println("Size of file is " +fileBytes.length);
System.out.println();
System.out.println("Start "+start +" end "+end);
byte[] bytes = getByteArray(fileBytes, start, end);
ByteArrayWrapper wrapper = new ByteArrayWrapper(bytes, sequenceNo);
return wrapper;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private byte[] getByteArray(byte[] bytes, long start, long end){
long arrayLength = end-start;
System.out.println("Start : "+start +" end : "+end + " Arraylength : "+arrayLength +" length of source array : "+bytes.length);
byte[] arr = new byte[(int)arrayLength];
for(int i = (int)start, j =0; i < end;i++,j++){
arr[j] = bytes[i];
}
return arr;
}
public static long fileSize(){
File file = new File(FILE_NAME);
return file.length();
}
}
FileReceiver.java - Этот класс получает файл.
Небольшое объяснение, что делает этот файл
- Этот класс находит размер файла, который нужно извлечь из Отправителя
- В зависимости от размера файла он находит начальную и конечную позиции до тех пор, пока не будут прочитаны байты.
- Он запускает n потоков, дающих начало, конец, порядковый номер каждого потока и список, который разделяют все потоки.
- Каждый поток читает количество байтов и создает ByteArrayWrapper.
- Объекты ByteArrayWrapper добавляются в список
- Тогда у меня есть цикл while, который в основном гарантирует, что все потоки сделали свою работу
- наконец, он сортирует список по порядковому номеру.
- затем байты объединяются, и формируется полный байтовый массив, который преобразуется в файл.
Код получателя файла
package com.filedownloader;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.zip.CRC32;
import org.apache.commons.io.FileUtils;
public class FileReceiver {
public static void main(String[] args) {
FileReceiver receiver = new FileReceiver();
receiver.receiveFile();
}
public void receiveFile(){
long startTime = System.currentTimeMillis();
long numberOfThreads = 10;
long filesize = FileSender.fileSize();
System.out.println("File size received "+filesize);
long start = filesize/numberOfThreads;
List<ByteArrayWrapper> list = new ArrayList<ByteArrayWrapper>();
for(long threadCount =0; threadCount<numberOfThreads ;threadCount++){
FileDownloaderTask task = new FileDownloaderTask(threadCount*start,(threadCount+1)*start,threadCount,list);
new Thread(task).start();
}
while(list.size() != numberOfThreads){
// this is done so that all the threads should complete their work before processing further.
//System.out.println("Waiting for threads to complete. List size "+list.size());
}
if(list.size() == numberOfThreads){
System.out.println("All bytes received "+list);
Collections.sort(list, new Comparator<ByteArrayWrapper>() {
@Override
public int compare(ByteArrayWrapper o1, ByteArrayWrapper o2) {
long sequence1 = o1.getSequence();
long sequence2 = o2.getSequence();
if(sequence1 < sequence2){
return -1;
}else if(sequence1 > sequence2){
return 1;
}
else{
return 0;
}
}
});
byte[] totalBytes = list.get(0).getBytes();
byte[] firstArr = null;
byte[] secondArr = null;
for(int i = 1;i<list.size();i++){
firstArr = totalBytes;
secondArr = list.get(i).getBytes();
totalBytes = concat(firstArr, secondArr);
}
System.out.println(totalBytes.length);
convertToFile(totalBytes,"c:\\tmp\\test.pdf");
long endTime = System.currentTimeMillis();
System.out.println("Total time taken with "+numberOfThreads +" threads is "+(endTime-startTime)+" ms" );
}
}
private byte[] concat(byte[] A, byte[] B) {
byte[] C= new byte[A.length+B.length];
System.arraycopy(A, 0, C, 0, A.length);
System.arraycopy(B, 0, C, A.length, B.length);
return C;
}
private void convertToFile(byte[] totalBytes,String name) {
try {
FileUtils.writeByteArrayToFile(new File(name), totalBytes);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
Код ByteArrayWrapper
package com.filedownloader;
import java.io.Serializable;
public class ByteArrayWrapper implements Serializable{
private static final long serialVersionUID = 3499562855188457886L;
private byte[] bytes;
private long sequence;
public ByteArrayWrapper(byte[] bytes, long sequenceNo) {
this.bytes = bytes;
this.sequence = sequenceNo;
}
public byte[] getBytes() {
return bytes;
}
public long getSequence() {
return sequence;
}
}
Код FileDownloaderTask
import java.util.List;
public class FileDownloaderTask implements Runnable {
private List<ByteArrayWrapper> list;
private long start;
private long end;
private long sequenceNo;
public FileDownloaderTask(long start,long end,long sequenceNo,List<ByteArrayWrapper> list) {
this.list = list;
this.start = start;
this.end = end;
this.sequenceNo = sequenceNo;
}
@Override
public void run() {
ByteArrayWrapper wrapper = new FileSender().sendBytesOfFile(start, end, sequenceNo);
list.add(wrapper);
}
}
Вопросы, связанные с этим кодом
Быстро ли загружается файл при использовании нескольких потоков? В этом коде я не вижу преимущества.
Как мне решить, сколько потоков я должен создать?
Являются ли они любыми библиотеками с открытым исходным кодом, которые делают это
Файл, который получает получатель файла, действителен и не поврежден, но контрольная сумма (я использовал FileUtils из common-io) не соответствует. В чем проблема?
Этот код освобождает память при использовании с большим файлом (более 100 МБ), т. Е. Потому что создается байтовый массив. Как я могу избежать?
Я знаю, что это очень плохой код, но я должен написать это за один день - :). Пожалуйста, предложите любой другой хороший способ сделать это?