這篇文章給大家介紹怎么在java中利用多線程下載圖片并壓縮,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對(duì)大家能有所幫助。
成都創(chuàng)新互聯(lián)是一家專注于網(wǎng)站制作、成都做網(wǎng)站與策劃設(shè)計(jì),嫩江網(wǎng)站建設(shè)哪家好?成都創(chuàng)新互聯(lián)做網(wǎng)站,專注于網(wǎng)站建設(shè)10多年,網(wǎng)設(shè)計(jì)領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:嫩江等地區(qū)。嫩江做網(wǎng)站價(jià)格咨詢:13518219792
使用框架:SpringMVC
定時(shí)任務(wù)實(shí)現(xiàn):繼承org.springframework.scheduling.quartz.QuartzJobBean;
ftp環(huán)境搭建就不說(shuō)了,在其他博客記錄過(guò),使用虛擬機(jī)中的CentOS搭建的FTP服務(wù),創(chuàng)建FTP賬號(hào)及對(duì)應(yīng)目錄,事先上傳需要下載的圖片地址文件。文件內(nèi)容格式“圖片ID||圖片地址”。
方法一、最簡(jiǎn)單的實(shí)現(xiàn)方法就是先下載存儲(chǔ)圖片url地址的文件,然后讀取文件遍歷圖片地址,調(diào)下載圖片的方法將圖片存儲(chǔ)到本地,最后壓縮下載的圖片,完成后刪除下載的圖片,只保留壓縮包。
public class PictureTransferJob extends QuartzJobBean { protected void executeInternal(JobExecutionContext arg0) throws JobExecutionException { //實(shí)際的FTP配置是讀取配置文件獲取的 //FTP地址 String hostName ="192.168.1.112"; //FTP端口 int port = 2001; /FTP賬號(hào) String userName = "test1"; //ftp密碼 String password = "test1"; //ftp文件存儲(chǔ)目錄 String ftpDowload = "/"; //文件本地存儲(chǔ)路徑 String path = this.getClass().getResource("/").getPath(); //圖片地址文件存儲(chǔ)目錄 String addrPath=path.substring(1, path.indexOf("WEB-INF/classes"))+"picAddr"; //實(shí)際下載的圖片存儲(chǔ)目錄 String picPath=path.substring(1, path.indexOf("WEB-INF/classes"))+"pic"; addrPath = addrPath.replace("%20"," "); picPath = picPath.replace("%20"," "); try { //創(chuàng)建存儲(chǔ)圖片地址的文件 creatFile(addrPath); //創(chuàng)建存儲(chǔ)實(shí)際圖片的文件 creatFile(picPath); String oldAddrPath = addrPath; String oldPicPath = picPath; //創(chuàng)建FTP連接 FtpUtil2 ftpUtil2 = new FtpUtil2(hostName, port,userName, password, ftpDowload, true); //遍歷FTP目錄下的文件 String[] files = ftpUtil2.ListAllFiles(); //本地?cái)?shù)據(jù)庫(kù)會(huì)有一個(gè)表記錄下載過(guò)的文件,這里會(huì)查詢數(shù)據(jù)庫(kù)和ftp列出的文件名比較,如果已經(jīng)下載過(guò)的文件就不會(huì)下載,避免重復(fù)下載。 //下面省略比較的過(guò)程,循環(huán)files數(shù)組,在本地創(chuàng)建文件 for(int i=0;i<files.length;i++){ creatFile(addrPath+File.separator+fileName); //ftpDowload是ftp服務(wù)器存儲(chǔ)文件的地址,addrPath是本地存儲(chǔ)文件的地址 //這里一個(gè)返回狀態(tài)判斷文件是否下載成功 boolean downloadInvestorFlag = ftpUtil2.downloadFile(ftpDowload, addrPath); //文件下載成功后調(diào)讀取文件的方法,將需要下載的圖片地址存入容器 boolean entityState = setPictureDetail(addrPath,picPath,fileNameDate); } } catch (Exception e) { e.printStackTrace(); //調(diào)記錄錯(cuò)誤日志的業(yè)務(wù)類用于發(fā)送下載文件出錯(cuò)的短信 } } //這里開始讀圖片地址 private boolean setPictureDetail(String addrPath,String picPath,String synDate) { System.out.println("----------進(jìn)入setPictureDetail方法-----------"); BufferedReader br = null; try { br=new BufferedReader(new InputStreamReader(new FileInputStream(addrPath),"UTF-8")); String row; int count=0; //map中存儲(chǔ)每行讀取到的圖片名稱和URL地址 Map<String, String> addrMap=new HashMap<String, String>(); while ((row=br.readLine())!=null) { try { count++; if (count==1) { continue; } String[] column = row.split("\\|\\|", -1); addrMap.put(column[0].trim(), column[1].trim()); } catch (Exception e) { e.printStackTrace(); } } System.out.println(new Date()); //這里調(diào)用壓縮方法,壓縮方法中會(huì)調(diào)用執(zhí)行下載圖片的方法 zipPic(picPath,synDate,addrMap); System.out.println(new Date()); System.out.println("----------完成--------------"); return true; } catch (Exception e) { e.printStackTrace(); //調(diào)用記錄錯(cuò)誤日志的業(yè)務(wù)類 return false; }finally { try { if (null != br) br.close(); } catch (IOException e) { e.printStackTrace(); } } } /** * 根據(jù)url地址下載圖片 * @throws IOException */ private boolean downPic(String picPath,List<Entry<String, String>> addrList,List<File> picList)throws IOException{ InputStream is=null; FileOutputStream fos=null; URL url=null; String fileName=null; String picAddr=null; File pic=null; try { for(Map.Entry<String, String> addrEntry:addrList) { fileName=addrEntry.getKey(); picAddr=addrEntry.getValue(); //創(chuàng)建Url對(duì)象 url=new URL(picAddr); is=url.openStream(); //URLConnection獲取到的流通過(guò)InputStream直接寫入字節(jié)數(shù)組會(huì)缺失數(shù)據(jù),導(dǎo)致下載的圖片不完整,使用org.apache.commons.io.IOUtils.toByteArray(urlconnection.openstream())可以解決 byte[] bytes=IOUtils.toByteArray(is);//new byte[is.available()];獲取的字節(jié) //流中數(shù)據(jù)讀入字節(jié)數(shù)組,讀入后,流中數(shù)據(jù)清空 pic=new File(picPath+fileName+".jpg"); fos=new FileOutputStream(pic); fos.write(bytes); //將下載的圖片存入List,待圖片全部下載完成后傳入zip方法進(jìn)行壓縮 picList.add(pic); fos.flush(); fos.close(); is.close(); } return true; } catch (Exception e) { e.printStackTrace(); return false; } finally{ if (null!=fos) { fos.close(); } if (null!=is) { is.close(); } } } //這里是壓縮文件的偽代碼 private void zipPic(picPath,synDate,addrMap);{ //傳入需要壓縮的文件列表和壓縮文件名 ZipUtil.zipByStream(picList,new File(picPath+synDate+".zip")); } /** * 創(chuàng)建文件 * @param path */ private void creatFile(String path) { File file = new File(path); if(!file.exists()) { file.mkdirs(); } } }
方法二、多線程下載、直接壓縮流
方法一雖然實(shí)現(xiàn)了基本功能,但是由于需要下載的圖片太多,以及壓縮本地圖片文件和刪除圖片也比較耗時(shí),所以可以優(yōu)化速度的地方有兩個(gè)。一個(gè)就是提高下載圖片的效率,一個(gè)就是提高壓縮的效率。
提高下載效率的方法可以使用多線程下載,提高壓縮效率的方法是可以不將圖片保存到本地而直接壓縮文件流。
多線程實(shí)現(xiàn)方式:首先我們保存了需要下載的文件的地址列表,我們要使用多線程下載就要保證不同線程下載的圖片不會(huì)重復(fù),因此需要一個(gè)標(biāo)志來(lái)區(qū)分,這時(shí)就可以使用一個(gè)索引計(jì)數(shù)器,按每個(gè)線程下載一定量圖片分割,從0開始,每隔比如400個(gè)圖片就用一個(gè)線程下載,這樣就可以確定需要的線程個(gè)數(shù),并且每個(gè)線程下載的圖片不會(huì)重復(fù)。
壓縮文件實(shí)現(xiàn)方式:因?yàn)樯蓧嚎s文件的本質(zhì)也是讀取需要壓縮的文件流,然后生成壓縮包,因此我們可以不創(chuàng)建下載的圖片文件,而直接使用容器存儲(chǔ)所有線程下載的圖片流數(shù)據(jù),然后將流數(shù)據(jù)傳給壓縮工具類直接壓縮,這樣就省略了讀取圖片文件創(chuàng)建流,然后生成壓縮包,再刪除本地圖片文件的繁瑣過(guò)程。
下面列出改造的主要實(shí)現(xiàn):
/** * 將下載的圖片按天壓縮 * @throws IOException */ private boolean zipPic(String picPath,String synDate,Map<String, String> addrMap) throws IOException{ //這里由于是多線程存儲(chǔ)圖片流,所以需要使用線程安全的map,因此使用ConcurrentHashMap Map<String,InputStream> pictureList=new ConcurrentHashMap<String,InputStream>(); //這里定義每個(gè)線程下載的圖片個(gè)數(shù) int count=400; //存儲(chǔ)需要下載的圖片地址 List<Entry<String, String>> addrList=new ArrayList<Entry<String, String>>(addrMap.entrySet()); //線程數(shù),加一是因?yàn)橐獎(jiǎng)?chuàng)建一個(gè)線程下載最后不足400個(gè)的圖片 int nThreads=(addrList.size()/count)+1; //CountDownLatch countDownLatch = new CountDownLatch(nThreads); try { boolean downPic=false; //執(zhí)行多線程下載圖片 downPic=downPic(picPath,addrList,picList,pictureList,nThreads,count); if (downPic) { ZipUtil.zipByArray(picList,new File(picPath+synDate+".zip")); } return true; } catch (Exception e) { e.printStackTrace(); return false; } }
下面是創(chuàng)建線程池
/** * 根據(jù)url地址下載圖片 * @throws InterruptedException */ private boolean downPic(String picPath,List<Entry<String, String>> addrList,Map<String, byte[]> picList,Map<String, InputStream> pictureList,int nThreads,int count)throws IOException, InterruptedException{ ExecutorService threadPool=Executors.newFixedThreadPool(nThreads); // 創(chuàng)建兩個(gè)個(gè)計(jì)數(shù)器 CountDownLatch begin=new CountDownLatch(0); CountDownLatch end=new CountDownLatch(nThreads); // 循環(huán)創(chuàng)建線程 for (int i = 0; i < nThreads; i++) { List<Entry<String, String>>subAddrList=null; // 計(jì)算每個(gè)線程執(zhí)行的數(shù)據(jù) if ((i + 1) == nThreads) { int startIndex = (i * count); int endIndex = addrList.size(); subAddrList = addrList.subList(startIndex, endIndex); } else { int startIndex = (i * count); int endIndex = (i + 1) * count; subAddrList = addrList.subList(startIndex, endIndex); } // 線程類 PicDownload mythead = new PicDownload(picPath,subAddrList,picList,pictureList); // 這里執(zhí)行線程的方式是調(diào)用線程池里的threadPool.execute(mythead)方法。 try { threadPool.execute(mythead); } catch (Exception e) { //記錄錯(cuò)誤日志 return false; } } begin.countDown(); end.await(); // 執(zhí)行完關(guān)閉線程池 threadPool.shutdown(); //這里一定要循環(huán)直到線程池中所有線程都結(jié)束才能往下走,測(cè)試時(shí)由于沒(méi)有這一步導(dǎo)致子線程下載圖片還沒(méi)完成,而主線程已經(jīng)往下走了,導(dǎo)致壓縮包內(nèi)沒(méi)有圖片 //也可以使用CountDownLatch實(shí)現(xiàn) /*while (true) { if (threadPool.isTerminated()) { System.out.println("所有子線程已結(jié)束!"); break; } }*/ return true; }
下面是線程實(shí)現(xiàn)
class PicDownload implements Runnable{ //下載圖片的地址列表 List<Entry<String, String>> addrList; //裝載下載成功的圖片列表 Map<String, byte[]> picList; Map<String, InputStream> pictureList; //圖片本地存儲(chǔ)路徑 String picPath; CountDownLatch begin,end; public PicDownload(String picPath,List<Entry<String, String>> addrList,Map<String, InputStream> picList,CountDownLatch begin,CountDownLatch end){ this.addrList=addrList; this.picList=picList; this.picPath=picPath; this.begin=begin; this.end=end; } @Override public void run() { try { System.out.println(Thread.currentThread().getName()+"------"+Thread.currentThread().getId()); downPicture(addrList); //System.out.println(countDownLatch.getCount()); begin.await(); } catch (Exception e) { e.printStackTrace(); }finally{ end.countDown(); //countDownLatch.countDown(); } } public boolean downPicture(List<Entry<String, String>> addrList) throws Exception{ InputStream is=null; FileOutputStream fos=null; URL url=null; String fileName=null; String picAddr=null; File pic=null; try { for(Map.Entry<String, String> addrEntry:addrList) { fileName=addrEntry.getKey(); picAddr=addrEntry.getValue(); //創(chuàng)建Url對(duì)象 url=new URL(picAddr); is=url.openStream(); //URLConnection獲取到的流通過(guò)InputStream直接寫入字節(jié)數(shù)組會(huì)缺失數(shù)據(jù),導(dǎo)致下載的圖片不完整,使用org.apache.commons.io.IOUtils.toByteArray(urlconnection.openstream())可以解決 //byte[] bytes=IOUtils.toByteArray(is);//new byte[is.available()];獲取的字節(jié) //流中數(shù)據(jù)讀入字節(jié)數(shù)組,讀入后,流中數(shù)據(jù)清空 picList.put(fileName+".jpg", is); //這時(shí)候由于沒(méi)有把流寫入文件,一定不能關(guān)閉流,否則流中的數(shù)據(jù)就會(huì)丟失 //is.close(); } return true; } catch (Exception e) { e.printStackTrace(); return false; } finally{ //不能關(guān)閉流 /*if (null!=is) { is.close(); }*/ } } }
上面使用流來(lái)壓縮遇到了另一個(gè)問(wèn)題,在壓縮文件時(shí)會(huì)出現(xiàn)java.net.SocketException:Connection reset
分析了一下原因,應(yīng)該是由于流InputStream和UrlConnection是連接狀態(tài)的,UrlConnection超時(shí)重置導(dǎo)致了獲取輸入流失敗。
嘗試設(shè)置URLConnection的超時(shí)時(shí)間,但是測(cè)試時(shí)發(fā)現(xiàn)圖片下載收到網(wǎng)速影響較大,這種方式很不穩(wěn)定,不可取,最后只有放棄使用流,而改用字節(jié)數(shù)組傳給壓縮工具類,然后將字節(jié)數(shù)組轉(zhuǎn)為流壓縮。
/** *使用容器存儲(chǔ)下載的圖片字節(jié)數(shù)組 */ public boolean downPicture(List<Entry<String, String>> addrList) throws Exception{ InputStream is=null; FileOutputStream fos=null; URL url=null; String fileName=null; String picAddr=null; File pic=null; try { for(Map.Entry<String, String> addrEntry:addrList) { fileName=addrEntry.getKey(); picAddr=addrEntry.getValue(); //創(chuàng)建Url對(duì)象 url=new URL(picAddr); //打開連接,創(chuàng)建java.net.URLConnection對(duì)象,該對(duì)象沒(méi)有關(guān)閉連接的方法,可以轉(zhuǎn)為它的子類HttpURLConnection調(diào)用disconnect方法關(guān)閉連接。 //java.net.URLConnection和java.net.HttpURLConnection都有設(shè)置超時(shí)時(shí)間的方法關(guān)閉連接 //HttpURLConnection uc=(HttpURLConnection)url.openConnection(); is=uc.getInputStream(); //URLConnection獲取到的流通過(guò)InputStream直接寫入字節(jié)數(shù)組會(huì)缺失數(shù)據(jù),導(dǎo)致下載的圖片不完整,使用org.apache.commons.io.IOUtils.toByteArray(urlconnection.openstream())可以解決 byte[] bytes=IOUtils.toByteArray(is);//new byte[is.available()];獲取的字節(jié) //流中數(shù)據(jù)讀入字節(jié)數(shù)組,讀入后,流中數(shù)據(jù)清空 //is.read(bytes); picList.put(fileName+".jpg",bytes); is.close(); } return true; } catch (Exception e) { e.printStackTrace(); return false; } finally{ if (null!=is) { is.close(); } } }
總結(jié):
實(shí)現(xiàn)過(guò)程中遇到的問(wèn)題:
1、使用線程池時(shí)對(duì)于共享狀態(tài),比如這里的存儲(chǔ)下載的圖片字節(jié)數(shù)據(jù)容器是所有線程共享的,因此需要使用同步的容器,否則會(huì)導(dǎo)致存儲(chǔ)的數(shù)據(jù)出問(wèn)題,因此使用了ConcurrentHashMap<String,byte[]>
2、這里存在一個(gè)主線程和子線程的執(zhí)行順序問(wèn)題,因?yàn)橹骶€程需要等待線程池中所有線程下載圖片結(jié)束后才能往下走去壓縮圖片,如果主線程不等待子線程結(jié)束就向下執(zhí)行壓縮方法就會(huì)導(dǎo)致壓縮圖片缺少或者沒(méi)有壓縮圖片。因此可以使用CountDownLatch實(shí)現(xiàn),或者在關(guān)閉線程池語(yǔ)句下面使用死循環(huán)檢查threadPool.isTerminated()才能繼續(xù)執(zhí)行主線程去壓縮圖片。
3、由于直接將UrlConnection獲取到的輸入流直接傳給壓縮類進(jìn)行壓縮,存在連接超時(shí)重置的情況,因此改用將下載的流存入字節(jié)數(shù)組,再傳給壓縮類壓縮,避免使用流出現(xiàn)意外情況。
4、在使用urlconnection.openStream()獲取輸入流后,轉(zhuǎn)換為字節(jié)數(shù)組下載的圖片是不完整的。。使用org.apache.commons.io.IOUtils.toByteArray(urlconnection.openstream())可以解決,具體可以閱讀其源碼看實(shí)現(xiàn)。
下面是FTP工具類的實(shí)現(xiàn):
import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPClientConfig; import org.apache.commons.net.ftp.FTPConnectionClosedException; import org.apache.commons.net.ftp.FTPReply; public class FtpUtil2 { private FTPClient ftpClient = null; // ftp服務(wù)器地址 private String hostName; // ftp服務(wù)器默認(rèn)端口 public static int defaultport = 21; // 登錄名 private String userName; // 登錄密碼 private String password; // 需要訪問(wèn)的遠(yuǎn)程目錄 private String remoteDir; /** * @param hostName * 主機(jī)地址 * @param port * 端口號(hào) * @param userName * 用戶名 * @param password * 密碼 * @param remoteDir * 默認(rèn)工作目錄 * @param is_zhTimeZone * 是否是中文FTP Server端 * @return * @return */ /** * 新增方法 */ public FtpUtil2() { PropConfig config = PropConfig.loadConfig("system.properties"); String hostName = config.getConfig("ftpAddress"); String port = config.getConfig("ftpPort"); String userName = config.getConfig("ftpUserName"); String password = config.getConfig("ftpPassword"); String remoteDir = config.getConfig("remoteFilePath"); boolean is_zhTimeZone= true; this.hostName = hostName; this.userName = userName; this.password = password; this.remoteDir = remoteDir == null ? "" : remoteDir; this.ftpClient = new FTPClient(); if (is_zhTimeZone) { this.ftpClient.configure(FtpUtil2.Config()); this.ftpClient.setControlEncoding("GBK"); } // 登錄 this.login(); // 切換目錄 this.changeDir(this.remoteDir); this.setFileType(FTPClient.BINARY_FILE_TYPE); ftpClient.setDefaultPort(Integer.parseInt(port)); } public FtpUtil2(String hostName, int port, String userName, String password, String remoteDir, boolean is_zhTimeZone) { this.hostName = hostName; this.userName = userName; this.password = password; defaultport=port; this.remoteDir = remoteDir == null ? "" : remoteDir; this.ftpClient = new FTPClient(); if (is_zhTimeZone) { this.ftpClient.configure(FtpUtil2.Config()); this.ftpClient.setControlEncoding("GBK"); } // 登錄 this.login(); // 切換目錄 this.changeDir(this.remoteDir); this.setFileType(FTPClient.ASCII_FILE_TYPE); ftpClient.setDefaultPort(port); } /** * 登錄FTP服務(wù)器 */ public boolean login() { boolean success = false; try { ftpClient.connect(this.hostName,defaultport); ftpClient.login(this.userName, this.password); int reply; reply = ftpClient.getReplyCode(); if (!FTPReply.isPositiveCompletion(reply)) { ftpClient.disconnect(); return success; } } catch (FTPConnectionClosedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } success = true; System.out.println("連接到ftp服務(wù)器:" + this.hostName + " 成功..開始登錄"); return success; } private static FTPClientConfig Config() { FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_UNIX); conf.setRecentDateFormatStr("MM月dd日 HH:mm"); // conf.setRecentDateFormatStr("(YYYY年)?MM月dd日( HH:mm)?"); return conf; } /** * 變更工作目錄 * * @param remoteDir * */ public void changeDir(String remoteDir) { try { this.remoteDir = remoteDir; ftpClient.changeWorkingDirectory(remoteDir); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("變更工作目錄為:" + remoteDir); } /** * 返回上一級(jí)目錄(父目錄) */ public void toParentDir() { try { ftpClient.changeToParentDirectory(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 列出當(dāng)前工作目錄下所有文件 */ public String[] ListAllFiles() { String[] names = this.ListFiles("*"); return this.sort(names); } /** * 列出指定工作目錄下的匹配文件 * * @param dir * exp: /cim/ * @param file_regEx * 通配符為* */ public String[] ListAllFiles(String dir, String file_regEx) { String[] names = this.ListFiles(dir + file_regEx); return this.sort(names); } /** * 列出匹配文件 * * @param file_regEx * 匹配字符,通配符為* */ public String[] ListFiles(String file_regEx) { try { /** * FTPFile[] remoteFiles = ftpClient.listFiles(file_regEx); * //System.out.println(remoteFiles.length); String[] name = new * String[remoteFiles.length]; if(remoteFiles != null) { for(int * i=0;i<remoteFiles.length;i++) { if(remoteFiles[i] == null) * name[i] = ""; else * if(remoteFiles[i].getName()==null||remoteFiles * [i].getName().equals * (".")||remoteFiles[i].getName().equals("..")) { name[i] = ""; * } else name[i] = remoteFiles[i].getName(); * System.out.println(name[i]); } } */ ftpClient.enterLocalPassiveMode(); String[] name = ftpClient.listNames(file_regEx);; if (name == null) return new String[0]; return this.sort(name); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return new String[0]; } public void Lists(String reg) { try { String[] a = ftpClient.listNames(reg); if (a != null) { for (String b : a) { System.out.println(b); } } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 設(shè)置傳輸文件的類型[文本文件或者二進(jìn)制文件] * * @param fileType * --BINARY_FILE_TYPE,ASCII_FILE_TYPE */ public void setFileType(int fileType) { try { ftpClient.setFileType(fileType); } catch (IOException e) { e.printStackTrace(); } } /** * 上傳文件 * * @param localFilePath * --本地文件路徑+文件名 * @param newFileName * --新的文件名 */ public void uploadFile(String localFilePath, String newFileName) { // 上傳文件 this.ftpClient.enterLocalPassiveMode();// 被動(dòng)模式連接 BufferedInputStream buffIn = null; try { buffIn = new BufferedInputStream(new FileInputStream(localFilePath)); boolean ifUpload = ftpClient.storeFile(newFileName, buffIn); if (!ifUpload) { System.out.println("上傳文件失敗。。。"); } else { System.out.println("上傳文件成功。。。"); } } catch (Exception e) { e.printStackTrace(); } finally { try { if (buffIn != null) buffIn.close(); } catch (Exception e) { e.printStackTrace(); } } } /** * 上傳文件2 * * @param file * --FileInputStream的文件 * @param newFileName * --新的文件名 */ public void newUploadFile(FileInputStream file, String newFileName) { // 上傳文件 this.ftpClient.enterLocalPassiveMode();// 被動(dòng)模式連接 BufferedInputStream buffIn = null; try { buffIn = new BufferedInputStream(file); boolean ifUpload = ftpClient.storeFile(newFileName, buffIn); if (!ifUpload) { System.out.println("上傳文件失敗。。。"); } else { System.out.println("上傳文件成功。。。"); } } catch (Exception e) { e.printStackTrace(); } finally { try { if (buffIn != null) buffIn.close(); } catch (Exception e) { e.printStackTrace(); } } } /** * 下載文件(單個(gè)) * * @param remoteFileName * --服務(wù)器上的文件名 * @param localFileName * --本地文件名 */ public boolean downloadFile(String remoteFileName, String localFileName) { this.ftpClient.enterLocalPassiveMode();// 被動(dòng)模式連接 BufferedOutputStream buffOut = null; try { buffOut = new BufferedOutputStream(new FileOutputStream( localFileName)); boolean ifDownload = ftpClient .retrieveFile(remoteFileName, buffOut); if (!ifDownload) { System.out.println("下載文件失敗。。。"); return false; } else { System.out.println("下載文件成功。。。"); } } catch (Exception e) { e.printStackTrace(); return false; } finally { try { if (buffOut != null) buffOut.close(); } catch (Exception e) { e.printStackTrace(); } } return true; } /** * 關(guān)閉FTP連接 */ public void close() { try { if (ftpClient != null) { ftpClient.logout(); ftpClient.disconnect(); } } catch (Exception e) { e.printStackTrace(); } } /** * 冒泡排序字符串(從大到小) */ public String[] sort(String[] str_Array) { if (str_Array == null) { throw new NullPointerException("The str_Array can not be null!"); } String tmp = ""; for (int i = 0; i < str_Array.length; i++) { for (int j = 0; j < str_Array.length - i - 1; j++) { if (str_Array[j].compareTo(str_Array[j + 1]) < 0) { tmp = str_Array[j]; str_Array[j] = str_Array[j + 1]; str_Array[j + 1] = tmp; } } } return str_Array; } public static void main(String[] strs) { FtpUtil2 FtpUtil2 = new FtpUtil2("192.168.1.112", 20011, "test1", "test1", "/", true); FtpUtil2.downloadFile("test.txt", "d:\\test.txt"); } }
下面是ZIP工具類:
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.Map; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; import org.apache.commons.io.IOUtils; import com.ibatis.common.logging.Log; import com.ibatis.common.logging.LogFactory; public class ZipUtil { private static final Log log = LogFactory.getLog(ZipUtil.class); /** * 壓縮文件 * * @param srcfile File[] 需要壓縮的文件列表 * @param zipfile File 壓縮后的文件 */ public static OutputStream zipFiles(List<File> srcfile, OutputStream outputStream) { byte[] buf = new byte[1024]; try { // Create the ZIP file ZipOutputStream out = new ZipOutputStream(outputStream); // Compress the files for (int i = 0; i < srcfile.size(); i++) { File file = srcfile.get(i); FileInputStream in = new FileInputStream(file); // Add ZIP entry to output stream. out.putNextEntry(new ZipEntry(file.getName())); // Transfer bytes from the file to the ZIP file int len; while ((len = in.read(buf)) > 0) { //System.out.println(len+"=============="); out.write(buf, 0, len); } // Complete the entry out.closeEntry(); in.close(); } // Complete the ZIP file out.close(); } catch (IOException e) { log.error("ZipUtil zipFiles exception:"+e); } return outputStream; } /** * 壓縮文件 * * @param srcfile File[] 需要壓縮的文件列表 * @param zipfile File 壓縮后的文件 */ public static void zipFiles(List<File> srcfile, File zipfile) { byte[] buf = new byte[1024]; try { // Create the ZIP file ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipfile)); // Compress the files for (int i = 0; i < srcfile.size(); i++) { File file = srcfile.get(i); FileInputStream in = new FileInputStream(file); // Add ZIP entry to output stream. out.putNextEntry(new ZipEntry(file.getName())); // Transfer bytes from the file to the ZIP file int len; while ((len = in.read(buf)) > 0) { out.write(buf, 0, len); } // Complete the entry out.closeEntry(); in.close(); } // Complete the ZIP file out.close(); } catch (IOException e) { log.error("ZipUtil zipFiles exception:"+e); } } /** * 壓縮文件 * srcfile:key:文件名,value:文件對(duì)應(yīng)的輸入流 * @param srcfile * @param zipfile * @see */ public static void zipByStream(Map<String,InputStream> srcfile, File zipfile) { try { // Create the ZIP file ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipfile)); // Compress the files System.out.println(srcfile.entrySet().size()); for (Map.Entry<String, InputStream> fileEntry:srcfile.entrySet()) { InputStream in = fileEntry.getValue(); // Add ZIP entry to output stream. System.out.println(in.available()); out.putNextEntry(new ZipEntry(fileEntry.getKey())); // Transfer bytes from the file to the ZIP file byte[] bytes=IOUtils.toByteArray(in); out.write(bytes); out.closeEntry(); in.close(); } // Complete the ZIP file out.close(); } catch (IOException e) { log.error("ZipUtil zipFiles exception:"+e); System.out.println(e.getMessage()); } } /** * 壓縮文件 * srcfile:key:文件名,value:文件對(duì)應(yīng)的字節(jié)數(shù)組 * @param srcfile * @param zipfile * @see */ public static void zipByArray(Map<String,byte[]> srcfile, File zipfile) { byte[] buf = new byte[1024]; try { // Create the ZIP file ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipfile)); // Compress the files System.out.println(srcfile.entrySet().size()); for (Map.Entry<String, byte[]> fileEntry:srcfile.entrySet()) { //InputStream in = fileEntry.getValue(); // Add ZIP entry to output stream. out.putNextEntry(new ZipEntry(fileEntry.getKey())); // Transfer bytes from the file to the ZIP file byte[] bytes=fileEntry.getValue();//IOUtils.toByteArray(in); out.write(bytes); out.closeEntry(); //in.close(); } // Complete the ZIP file out.close(); } catch (IOException e) { log.error("ZipUtil zipFiles exception:"+e); System.out.println(e.getMessage()); } } /** * 解壓縮 * * @param zipfile File 需要解壓縮的文件 * @param descDir String 解壓后的目標(biāo)目錄 */ public static void unZipFiles(File zipfile, String descDir) { try { // Open the ZIP file ZipFile zf = new ZipFile(zipfile); for (Enumeration entries = zf.entries(); entries.hasMoreElements();) { // Get the entry name ZipEntry entry = ((ZipEntry) entries.nextElement()); String zipEntryName = entry.getName(); InputStream in = zf.getInputStream(entry); // System.out.println(zipEntryName); OutputStream out = new FileOutputStream(descDir + zipEntryName); byte[] buf1 = new byte[1024]; int len; while ((len = in.read(buf1)) > 0) { out.write(buf1, 0, len); } // Close the file and stream in.close(); out.close(); } } catch (IOException e) { log.error("ZipUtil unZipFiles exception:"+e); } } /** * Main * * @param args */ public static void main(String[] args) { List<File> srcfile=new ArrayList<File>(); srcfile.add(new File("d:\\1.jpg")); srcfile.add(new File("d:\\2.jpg")); srcfile.add(new File("d:\\3.jpg")); srcfile.add(new File("d:\\4.jpg")); File zipfile = new File("d:\\pic.zip"); ZipUtil.zipFiles(srcfile, zipfile); } }
Java中的集合主要分為四類:1、List列表:有序的,可重復(fù)的;2、Queue隊(duì)列:有序,可重復(fù)的;3、Set集合:不可重復(fù);4、Map映射:無(wú)序,鍵唯一,值不唯一。
關(guān)于怎么在java中利用多線程下載圖片并壓縮就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。
分享名稱:怎么在java中利用多線程下載圖片并壓縮
文章地址:http://vcdvsql.cn/article38/jhiipp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制網(wǎng)站、網(wǎng)頁(yè)設(shè)計(jì)公司、關(guān)鍵詞優(yōu)化、企業(yè)網(wǎng)站制作、微信小程序、企業(yè)建站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)