From 4fc6948b6a7314a3a08937884989f511607f7921 Mon Sep 17 00:00:00 2001 From: xuxiqoqing Date: Sun, 12 Mar 2017 17:27:43 +0800 Subject: [PATCH] L3 --- .../github/vxzh/download/DownloadThread.java | 40 ++ .../github/vxzh/download/FileDownloader.java | 76 ++++ .../vxzh/download/FileDownloaderTest.java | 52 +++ .../io/github/vxzh/download/LinkedList.java | 354 ++++++++++++++++++ .../github/vxzh/download/api/Connection.java | 26 ++ .../download/api/ConnectionException.java | 9 + .../vxzh/download/api/ConnectionManager.java | 11 + .../vxzh/download/api/DownloadListener.java | 7 + .../vxzh/download/impl/ConnectionImpl.java | 76 ++++ .../download/impl/ConnectionManagerImpl.java | 21 ++ 10 files changed, 672 insertions(+) create mode 100644 group13/2729382520/L3/src/io/github/vxzh/download/DownloadThread.java create mode 100644 group13/2729382520/L3/src/io/github/vxzh/download/FileDownloader.java create mode 100644 group13/2729382520/L3/src/io/github/vxzh/download/FileDownloaderTest.java create mode 100644 group13/2729382520/L3/src/io/github/vxzh/download/LinkedList.java create mode 100644 group13/2729382520/L3/src/io/github/vxzh/download/api/Connection.java create mode 100644 group13/2729382520/L3/src/io/github/vxzh/download/api/ConnectionException.java create mode 100644 group13/2729382520/L3/src/io/github/vxzh/download/api/ConnectionManager.java create mode 100644 group13/2729382520/L3/src/io/github/vxzh/download/api/DownloadListener.java create mode 100644 group13/2729382520/L3/src/io/github/vxzh/download/impl/ConnectionImpl.java create mode 100644 group13/2729382520/L3/src/io/github/vxzh/download/impl/ConnectionManagerImpl.java diff --git a/group13/2729382520/L3/src/io/github/vxzh/download/DownloadThread.java b/group13/2729382520/L3/src/io/github/vxzh/download/DownloadThread.java new file mode 100644 index 0000000000..2a67e5dbbf --- /dev/null +++ b/group13/2729382520/L3/src/io/github/vxzh/download/DownloadThread.java @@ -0,0 +1,40 @@ +package io.github.vxzh.download; + +import io.github.vxzh.download.api.Connection; + +import java.io.RandomAccessFile; +import java.util.concurrent.CyclicBarrier; + +public class DownloadThread extends Thread { + + private Connection conn; + private int startPos; + private int endPos; + private CyclicBarrier barrier; + + public DownloadThread(Connection conn, int startPos, int endPos, CyclicBarrier barrier) { + + this.conn = conn; + this.startPos = startPos; + this.endPos = endPos; + this.barrier = barrier; + } + + public void run() { + + try { + + byte[] buffer = conn.read(startPos, endPos); + RandomAccessFile raf = new RandomAccessFile("/Users/xuxiaoqing/Documents/demo.jpg", "rw"); + raf.seek(startPos); + raf.write(buffer, 0, buffer.length); + //raf.write(buffer); + raf.close(); + barrier.await(); + + } catch (Exception e) { + e.printStackTrace(); + } + + } +} \ No newline at end of file diff --git a/group13/2729382520/L3/src/io/github/vxzh/download/FileDownloader.java b/group13/2729382520/L3/src/io/github/vxzh/download/FileDownloader.java new file mode 100644 index 0000000000..23b6327c05 --- /dev/null +++ b/group13/2729382520/L3/src/io/github/vxzh/download/FileDownloader.java @@ -0,0 +1,76 @@ +package io.github.vxzh.download; + +import io.github.vxzh.download.api.Connection; +import io.github.vxzh.download.api.ConnectionManager; +import io.github.vxzh.download.api.DownloadListener; + +import java.util.concurrent.CyclicBarrier; + +public class FileDownloader { + + private String path; + + private DownloadListener listener; + + private ConnectionManager cm; + + private static final int THREAD_NUM = 3; + + public FileDownloader(String path) { + this.path = path; + + } + + public void execute() { + + CyclicBarrier barrier = new CyclicBarrier(THREAD_NUM, new Runnable() { + @Override + public void run() { + listener.notifyFinished(); + } + }); + + Connection conn = null; + try { + + conn = cm.open(this.path); + //实际的文件长度 + int length = conn.getContentLength(); + //平均每一个线程下载的文件大小. + int blockSize = length / THREAD_NUM; + for (int threadId = 1; threadId <= THREAD_NUM; threadId++) { + int startIndex = (threadId - 1) * blockSize; + int endIndex = threadId * blockSize - 1; + //最后一个线程下载的长度 + if (threadId == THREAD_NUM) { + endIndex = length - 1; + } + + System.out.println("线程:" + threadId + "下载:---" + startIndex + "--->" + endIndex); + new DownloadThread(conn, startIndex, endIndex, barrier).start(); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (conn != null) { + conn.close(); + } + } + + + } + + public void setListener(DownloadListener listener) { + this.listener = listener; + } + + + public void setConnectionManager(ConnectionManager ucm) { + this.cm = ucm; + } + + public DownloadListener getListener() { + return this.listener; + } + +} diff --git a/group13/2729382520/L3/src/io/github/vxzh/download/FileDownloaderTest.java b/group13/2729382520/L3/src/io/github/vxzh/download/FileDownloaderTest.java new file mode 100644 index 0000000000..8f926c4875 --- /dev/null +++ b/group13/2729382520/L3/src/io/github/vxzh/download/FileDownloaderTest.java @@ -0,0 +1,52 @@ +package io.github.vxzh.download; + +import io.github.vxzh.download.api.ConnectionManager; +import io.github.vxzh.download.api.DownloadListener; +import io.github.vxzh.download.impl.ConnectionManagerImpl; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class FileDownloaderTest { + private boolean downloadFinished = false; + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testDownload() { + + String url = "http://c.hiphotos.baidu.com/zhidao/pic/item/29381f30e924b8999bfaab046d061d950b7bf6cc.jpg"; + + FileDownloader downloader = new FileDownloader(url); + ConnectionManager cm = new ConnectionManagerImpl(); + downloader.setConnectionManager(cm); + + downloader.setListener(new DownloadListener() { + @Override + public void notifyFinished() { + downloadFinished = true; + } + + }); + + downloader.execute(); + + // 等待多线程下载程序执行完毕 + while (!downloadFinished) { + try { + System.out.println("还没有下载完成,休眠五秒"); + //休眠5秒 + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + System.out.println("下载完成!"); + } +} \ No newline at end of file diff --git a/group13/2729382520/L3/src/io/github/vxzh/download/LinkedList.java b/group13/2729382520/L3/src/io/github/vxzh/download/LinkedList.java new file mode 100644 index 0000000000..0ab689946b --- /dev/null +++ b/group13/2729382520/L3/src/io/github/vxzh/download/LinkedList.java @@ -0,0 +1,354 @@ +package io.github.vxzh.download; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; + +public class LinkedList implements List { + + private Node head; + private int size; + + @Override + public boolean remove(Object o) { + return false; + } + + @Override + public boolean isEmpty() { + return size == 0; + } + + + @Override + public boolean contains(Object o) { + return false; + } + + @Override + public void clear() { + + } + + /** + * 从头部添加节点 + * + * @return + */ + public boolean add(E o) { + Node node = new Node(); + node.data = o; + if (null == head) { + head = node; + } else { + node.next = head.next; + head.next = node; + } + size++; + return true; + } + + @Override + public void set(int index, E e) { + checkIndex(index); + Node node = new Node(); + node.data = e; + Node prev = node(index - 1); + node.next = prev.next; + prev.next = node; + + } + + public E get(int index) { + checkIndex(index); + return (E) node(index).data; + } + + public E remove(int index) { + checkIndex(index); + if (0 == index) { + E data = head.data; + head = head.next; + return data; + } + Node prev = node(index - 1); + E data = (E) prev.next.data; + Node current = prev.next; + prev.next = current.next; + current.next = null; + return data; + } + + public int size() { + return size; + } + + public void addLast(E o) { + Node node = new Node(); + node.data = o; + + if (size == 0) { + head = node; + } else { + Node last = node(size - 1); + last.next = node; + } + size++; + } + + public E removeFirst() { + checkIndex(0); + E data = head.data; + head = head.next; + size--; + return data; + } + + public E removeLast() { + if (size == 0) { + return removeFirst(); + } + + Node node = node(size - 2); + E data = (E) node.next.data; + node.next = null; + size--; + return data; + } + + public Iterator iterator() { + return new It(); + } + + private void checkIndex(int index) { + if (index < 0 || index > size - 1) { + throw new NoSuchElementException("index " + index + " not found!"); + } + } + + private class It implements Iterator { + Node currentNode = head; + int currentIndex; + + @Override + public boolean hasNext() { + return currentIndex < size - 1; + } + + @Override + public E next() { + currentNode = currentNode.next; + currentIndex++; + return currentNode.data; + } + + @Override + public void remove() { + if (currentIndex == 0) { + removeFirst(); + } else { + Node prev = node(currentIndex - 1); + Node cur = prev.next; + cur.next = null; + prev.next = cur.next; + size--; + } + + } + + } + + private Node node(int index) { + Node current = head; + for (int i = 0; i < size; i++) { + if (index == i) { + return current; + } + current = current.next; + } + return null; + } + + private static class Node { + E data; + Node next; + + } + + /** + * 把该链表逆置 + * 例如链表为 3->7->10 , 逆置后变为 10->7->3 + */ + public void reverse() { + + } + + /** + * 删除一个单链表的前半部分 + * 例如:list = 2->5->7->8 , 删除以后的值为 7->8 + * 如果list = 2->5->7->8->10 ,删除以后的值为7,8,10 + */ + public void removeFirstHalf() { + if (isEmpty()) { + return; + } + int half = size / 2; + + Node current = head; + for (int i = 0; i < half; i++) { + Node next = current.next; + current.next = null; + current = next; + } + } + + /** + * 从第i个元素开始, 删除length 个元素 , 注意i从0开始 + * + * @param i + * @param length + */ + public void remove(int i, int length) { + checkIndex(i); + if (i + length > size) { + throw new NoSuchElementException("要删除的元素不存在!"); + } + + Node current = node(i); + for (int index = i; index <= length; index++) { + Node next = current.next; + current.next = null; + current = next; + } + + } + + /** + * 假定当前链表和list均包含已升序排列的整数 + * 从当前链表中取出那些list所指定的元素 + * 例如当前链表 = 11->101->201->301->401->501->601->701 + * listB = 1->3->4->6 + * 返回的结果应该是[101,301,401,601] + * + * @param list + */ + public static int[] getElements(LinkedList list) { + List listB = new ArrayList(); + + int[] array = new int[listB.size()]; + for (int i = 0; i < array.length; i++) { + array[i] = (Integer) list.get(i); + } + return array; + } + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 从当前链表中中删除在list中出现的元素 + * + * @param list + */ + + public void subtract(LinkedList list) { + Node prev = head; + + while (prev.next != null) { + if (list.contains(prev.next.data)) { + Node current = prev.next; + prev.next = current.next; + current.next = null; + } + } + prev = head; + if (prev.data == prev.next.data) { + head = prev.next; + prev.next = null; + prev = head; + } + } + + /** + * 已知当前链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 删除表中所有值相同的多余元素(使得操作后的线性表中所有元素的值均不相同) + */ + public void removeDuplicateValues() { + Node prev = head; + + while (prev.next != null) { + Node current = prev.next; + if (prev.data == prev.next.data) {//如果前一个的data与当前节点的data同等,就删除当前的 + prev.next = current.next; + current.next = null; + } + } + } + + /** + * 已知链表中的元素以值递增有序排列,并以单链表作存储结构。 + * 试写一高效的算法,删除表中所有值大于min且小于max的元素(若表中存在这样的元素) + * + * @param min + * @param max + */ + public void removeRange(int min, int max) { + Node prev = head; + + while (prev.next != null) {//先删除头节点之后的 + Node current = prev.next; + if (min < (Integer) prev.data && (Integer) prev.data < max) { + prev.next = current.next; + current.next = null; + } + + } + prev = head; + if (min < (Integer) prev.data && (Integer) prev.data < max) {//如果头节点满足条件,删除头节点 + head = prev.next; + prev.next = null; + prev = head; + } + + } + + /** + * 假设当前链表和参数list指定的链表均以元素依值递增有序排列(同一表中的元素值各不相同) + * 现要求生成新链表C,其元素为当前链表和list中元素的交集,且表C中的元素有依值递增有序排列 + * + * @param list + */ + public LinkedList intersection(LinkedList list) { + LinkedList ret = new LinkedList(); + + Iterator it1 = list.iterator(); + Iterator it2 = this.iterator(); + + E data1 = it1.hasNext() ? it1.next() : null; + E data2 = it2.hasNext() ? it2.next() : null; + while (it1.hasNext() || it2.hasNext()) { + + + if (data1 == null && data2 != null) { + ret.add(data2); + data2 = it2.hasNext() ? it2.next() : null; + } else if (data2 == null && data1 != null) { + ret.add(data1); + data1 = it1.hasNext() ? it1.next() : null; + } else {// if(data1 != null && data2 != null) + if (data1.compareTo(data2) < 0) { + ret.add(data1); + data1 = it1.hasNext() ? it1.next() : null; + } else if (data1.compareTo(data2) > 0) { + ret.add(data2); + data2 = it2.hasNext() ? it2.next() : null; + } else {//equal + ret.add(data1); + data1 = it1.hasNext() ? it1.next() : null; + data2 = it2.hasNext() ? it2.next() : null; + } + } + } + + return ret; + } +} diff --git a/group13/2729382520/L3/src/io/github/vxzh/download/api/Connection.java b/group13/2729382520/L3/src/io/github/vxzh/download/api/Connection.java new file mode 100644 index 0000000000..d91930a36a --- /dev/null +++ b/group13/2729382520/L3/src/io/github/vxzh/download/api/Connection.java @@ -0,0 +1,26 @@ +package io.github.vxzh.download.api; + +import java.io.IOException; + +public interface Connection { + /** + * 给定开始和结束位置, 读取数据, 返回值是字节数组 + * + * @param startPos 开始位置, 从0开始 + * @param endPos 结束位置 + * @return + */ + byte[] read(int startPos, int endPos) throws IOException,ConnectionException; + + /** + * 得到数据内容的长度 + * + * @return + */ + int getContentLength(); + + /** + * 关闭连接 + */ + void close(); +} \ No newline at end of file diff --git a/group13/2729382520/L3/src/io/github/vxzh/download/api/ConnectionException.java b/group13/2729382520/L3/src/io/github/vxzh/download/api/ConnectionException.java new file mode 100644 index 0000000000..5ed88448c2 --- /dev/null +++ b/group13/2729382520/L3/src/io/github/vxzh/download/api/ConnectionException.java @@ -0,0 +1,9 @@ +package io.github.vxzh.download.api; + +public class ConnectionException extends Exception { + + public ConnectionException(String msg) { + super(msg); + } + +} diff --git a/group13/2729382520/L3/src/io/github/vxzh/download/api/ConnectionManager.java b/group13/2729382520/L3/src/io/github/vxzh/download/api/ConnectionManager.java new file mode 100644 index 0000000000..d019a9c1a1 --- /dev/null +++ b/group13/2729382520/L3/src/io/github/vxzh/download/api/ConnectionManager.java @@ -0,0 +1,11 @@ +package io.github.vxzh.download.api; + +public interface ConnectionManager { + /** + * 给定一个url , 打开一个连接 + * + * @param url + * @return + */ + Connection open(String url) throws ConnectionException; +} diff --git a/group13/2729382520/L3/src/io/github/vxzh/download/api/DownloadListener.java b/group13/2729382520/L3/src/io/github/vxzh/download/api/DownloadListener.java new file mode 100644 index 0000000000..d34556b38a --- /dev/null +++ b/group13/2729382520/L3/src/io/github/vxzh/download/api/DownloadListener.java @@ -0,0 +1,7 @@ +package io.github.vxzh.download.api; + +public interface DownloadListener { + + void notifyFinished(); + +} diff --git a/group13/2729382520/L3/src/io/github/vxzh/download/impl/ConnectionImpl.java b/group13/2729382520/L3/src/io/github/vxzh/download/impl/ConnectionImpl.java new file mode 100644 index 0000000000..2981d5a2aa --- /dev/null +++ b/group13/2729382520/L3/src/io/github/vxzh/download/impl/ConnectionImpl.java @@ -0,0 +1,76 @@ +package io.github.vxzh.download.impl; + +import io.github.vxzh.download.api.Connection; +import io.github.vxzh.download.api.ConnectionException; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; + +public class ConnectionImpl implements Connection { + + + private String path; + + private static final int BUFFER_MAX_SIZE = 1024; + + public ConnectionImpl(String path) { + this.path = path; + } + + @Override + public byte[] read(int startPos, int endPos) throws IOException, ConnectionException { + + if (startPos > endPos) + throw new ConnectionException("startPos > endPos "); + + URL url = new URL(path); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setConnectTimeout(5000); + conn.setRequestMethod("GET"); + conn.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos); + int responseCode = conn.getResponseCode(); + if (responseCode == HttpURLConnection.HTTP_PARTIAL) { + int blockSize = endPos - startPos + 1; + InputStream is = conn.getInputStream(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + byte[] buffer = new byte[Math.min(blockSize, BUFFER_MAX_SIZE)]; + int len = -1; + while ((len = is.read(buffer)) != -1) { + outputStream.write(buffer, 0, len); + } + outputStream.close(); + is.close(); + return outputStream.toByteArray(); + + + } else { + throw new ConnectionException("response code: " + responseCode); + } + + + } + + @Override + public int getContentLength() { + HttpURLConnection conn = null; + try { + URL url = new URL(path); + conn = (HttpURLConnection) url.openConnection(); + conn.setConnectTimeout(5000); + conn.setRequestMethod("GET"); + + } catch (Exception e) { + e.printStackTrace(); + } + return conn.getContentLength(); + } + + @Override + public void close() { + + } + +} diff --git a/group13/2729382520/L3/src/io/github/vxzh/download/impl/ConnectionManagerImpl.java b/group13/2729382520/L3/src/io/github/vxzh/download/impl/ConnectionManagerImpl.java new file mode 100644 index 0000000000..100e550bec --- /dev/null +++ b/group13/2729382520/L3/src/io/github/vxzh/download/impl/ConnectionManagerImpl.java @@ -0,0 +1,21 @@ +package io.github.vxzh.download.impl; + +import io.github.vxzh.download.api.Connection; +import io.github.vxzh.download.api.ConnectionException; +import io.github.vxzh.download.api.ConnectionManager; + +public class ConnectionManagerImpl implements ConnectionManager { + + @Override + public Connection open(String path) throws ConnectionException { + + ConnectionImpl connection = null; + try { + connection = new ConnectionImpl(path); + } catch (Exception e) { + e.printStackTrace(); + } + return connection; + } + +} \ No newline at end of file