注:本文出自coder-pig
原文鏈接:http://blog.csdn.net/coder_pig/article/details/45248445
很快要到I/O流了,都是重要的內容,而且內容很多有難度的哦,如果是小花自己寫不知能否堅持下去,感謝小豬的這些文章,他可是花了很多心思,整個人都老了一大截,希望大家能好好看看,不枉他老人家一片苦心。。。
本節引言:
兜兜轉轉,又回來寫Java了,上一篇J2SE知識點歸納筆記(六)---Java常用類是上2014.4.14寫的,時隔一年
又來重拾之前還沒寫完的系列了,前些天羣裏一個妹子反映她Java基礎薄弱,然後抱怨在csdn上找不到J2SE的
系列教程,J2SE簡單嘛,個個都懶得寫...真的簡單麼?或許吧...今天剛寫完論文初稿,也算稍微輕鬆了那麼一點,
白天上班,晚上趕論文,痛苦的一個星期也算到頭了...趁着臨近週末,小豬也來動下筆墨吧,(*^__^*) 嘻嘻……
哪怕有一個讀者,小豬也會堅持寫下去的。好了,嘮叨的廢話就說到這。本節要學習的東西:
Java IO,一說到IO,估計大家第一時間想起的就是:流,輸入輸出流,字符流,字節流等等,是吧,但是本節先不講
流,先來點開胃菜,介紹兩個文件IO的類: File(文件類)與RandomAccessFile(隨機訪問文件類),開始本節內容~
ps:另外說下Java IO相關的類和接口都放在java.io包下,大家要養成查API的習慣哦~
本節正文:
1.File(文件類):
1)File類的定義:
描述文件的相關特性,比如:是否可讀,可寫,文件大小等特性的一個類
2)創建File類對象時要注意的地方:
答:首先我們要區分兩個名詞:"絕對路徑"和"相對路徑"
絕對路徑——即完整的路徑,比如:D:\MyCode\Java\FileDemo
相對路徑——會在代碼所在的地方生成,比如:res/jay.txt 就會在你代碼的目錄下成jay.txt文件
另外,還有注意一點,文件的路徑與Windows下不同,"\"要寫成'/'或者"\\"不然會報錯的喔~
如果,你想保險點,讓程序跨平臺的話,比如在linux下就和Windows不一樣的,Linux下是"/"
解決方法就是使用File給我們提供的兩個常量,他們分別是:
File.separator: "\" File.pathSeparator:";"
如果我們是直接自己拼的話,在window下,在D盤下我們要創建一個Jay.txt文件要這樣寫:
File f=new File("D:\\Jay.txt"); 如果在Linux下呢?要寫成 //
如果我們用使用上面的兩個常量的話,我們無需理在什麼系統下,直接:
String fileName="D:"+File.separator+"Jay.txt";
File f=new File(fileName);
打印下fileName:
好了,記得把這兩個變量Mark下來哦~
3)File的常見方法:
1)判斷文件或者目錄是否存在: exists()
2)判斷是否爲目錄: isDirectory()
3)判斷是否爲文件: isFile()
4)判斷文件是否可讀: canRead()
5)判斷文件是否可寫: canWrite()
6)判斷文件是否隱藏: isHidden()
7)判斷文件路徑是否爲絕對路徑: isAbsolute()
8)判斷文件路徑是否相同: equals():返回true,false
compareTo():是否相等,相等返回0,小於返回負數,大於返回正數
9)獲取文件的絕對路徑: getAbsolutePath()
10)獲取文件名稱: getName()
11)獲取文件大小: length()
12)獲取文件最後被修改的時間 : lastModified()
13)獲取文件的路徑: getPath()
14)獲取文件的上層文件的目錄: getParent()
15)創建一個新文件: createNewFile()
16)創建一個新目錄: mkdir()
17)刪除文件或目錄: delete()
18)修改文件的名稱: renameTo(str)
19)修改文件爲只讀: setReadOnly()
20)修改最後的修改時間: setLastModified(long time)
4)File的使用示例:
①創建一個文件:
- public void newFile(String fileName)throws Exception
- {
- File f=new File(fileName);
- f.createNewFile();
- }
②刪除一個文件:
- public void deleteFile(String fileName)
- {
- File f=new File(fileName);
- if(f.exists())f.delete();
- else System.out.println("文件不存在");
- }
③創建一個文件夾:
- public void newDir(String fileName)
- {
- //fileName寫文件夾名哦,比如:D:\Test
- File f=new File(fileName);
- f.mkdir();
- }
④刪除文件夾
刪除文件夾的方法和刪除文件是一樣的,都是調用delete( )方法,空文件夾可以直接刪除,
但是有一點要注意的是,非空文件夾是不能直接刪除的哦!!!我們需要先把裏面的文件都
刪除了,才能刪除文件夾哦,那麼現在我們要做的是,就是刪除文件夾裏的文件咯,如果
有幾層怎麼破?我們需要考慮這個問題,這裏的話,如果我們使用遞歸的話,就很容易解決
這個問題了,代碼如下:
- import java.io.File;
- public class RemoveDir {
- public static void main(String[] args) {
- File file = new File("D:\\Test");
- removeDir(file);
- }
- public static void removeDir(File file) {
- File[] files = file.listFiles();
- for (File f : files) {
- if (f.isDirectory())// 遞歸調用
- {
- removeDir(f);
- } else {
- f.delete();
- }
- }
- // 一層目錄下的內容都刪除以後,刪除掉這個文件夾
- file.delete();
- }
- }
好吧,遞歸就是這麼奇妙~
⑤判斷路徑是否爲文件夾(目錄):
- public boolean isDir(String fileName)
- {
- File f=new File(fileName);
- if(f.isDirectory()){
- <span style="white-space:pre"> </span>return true;
- <span style="white-space:pre"> </span>}
- return false;
- }
⑥遍歷某文件夾下所有文件(文件名,包含隱藏文件):
- public void getAllFile1(String fileName) {
- File f = new File(fileName);
- String[] str = f.list();
- for (int i = 0; i < str.length; i++) {
- System.out.println(str[i]);
- }
- }
⑦遍歷某文件夾下所有文件(包括完整路徑,包含隱藏文件)
- public void getAllFile2(String fileName) {
- File f = new File(fileName);
- File[] str = f.listFiles();
- for (int i = 0; i < str.length; i++) {
- System.out.println(str[i]);
- }
- }
⑧遍歷某目錄下的全部文件(包含子目錄,完整路徑,隱藏文件)
還是用到我們的遞歸:
- /*
- * 獲取某目錄下的全部文件(包含子目錄,完整路徑,隱藏文件)
- * */
- public void getAllFile3(File file) {
- if(file != null){
- if(file.isDirectory()){
- File[] fileArray=file.listFiles();
- if(fileArray!=null){
- for (int i = 0; i < fileArray.length; i++) {
- //遞歸調用
- getAllFile3(fileArray[i]);
- }
- }
- }
- else{
- System.out.println(file);
- }
- }
- }
5)學以致用的兩個小例子:
①遍歷某個文件夾下特定的文件
比如某個目錄下的所有.zip文件,筆者的電腦下載了很多編程視頻,
我們想遍歷查看所有.zip的文件的名稱:
核心是:判斷是否爲目錄,文件名的篩選
好吧,下面我們就來實現吧:
- /*
- * 遍歷某目錄下特定文件的文件名與路徑
- */
- public static void getSpecificFile(File file, String suffix) {
- if (file != null) {
- if (file.isDirectory()) {
- File[] fileArray = file.listFiles();
- String name1 = file.getName();
- System.out.println("——————" + name1);
- if (fileArray != null) {
- for (int i = 0; i < fileArray.length; i++) {
- // 遞歸調用
- getSpecificFile(fileArray[i], suffix);
- }
- }
- } else {
- if (file.getName().toString().endsWith(suffix)) {
- System.out.print(" ");
- System.out.println(file
- .getName()
- .toString()
- .substring(
- 0,
- file.getName().toString().length()
- - suffix.length()));
- }
- }
- }
- }
部分運行截圖:
②批量文件命名:
比如我們寫App的時候,下載了一大堆了素材圖片:
而下載的時候:他們的文件名是這樣的:
我們是想把他們作爲頭像的,我們想把他們改成head1.png,head2.png...這種文件名格式的,
難道我們一個個手動的去改麼=-=,如果這些圖標有上百個,改到什麼時候呢?
學以致用,這裏我們就來實現簡單的批量文件名修改:
比如我們這裏需要批量修改下述的圖標:
代碼實現:
- /**
- * 批量修改文件名:
- * @param filename 要是目錄哦!
- */
- public static boolean changeFileNames(String fileName,String suffix)
- {
- File f = new File(fileName);
- if(!f.isDirectory())
- {
- return false;
- }
- int j = 0;
- File[] fs = f.listFiles();
- for(int i = 0;i < fs.length;i++)
- {
- String str = fs[i].getName();
- if(str.endsWith(suffix))
- {
- fs[i].renameTo(new File(fileName + File.separator +"head" + j +suffix));
- / System.out.println(fileName + File.separator +"head" + j +suffix);
- j++;
- }
- }
- return true;
- }
運行後:
好了,就是那麼簡單,是不是又有趣呢?這裏並沒有都是一些簡單的東西,筆者可以根據自己的需要,
進行拓展,比如遍歷文件後,生成另外的txt文件而不是直接打印到屏幕上等....
2.RandomAccessFile類
1)這個類是幹嘛的?
隨機訪問文件類,其實和File的功能類似,都是用於操作文件,但是RandomAccessFile類
有seek( )方法來訪問文件,可以從文件的任意位置讀寫文件,這個seek可以看做文件指針吧,
而這個類,我們用的最多的無疑是:Java多線程文件下載~
ps:其實這個小豬已經在Android入門之路的day 8寫過了,這裏就再貼一遍哈,別怪小豬偷懶哈,
另外這個多線程下載的話,文件小的話效果不大哦~比如下個1,2mb的東西....另外示例給的是
Tomact搭建的web空項目,要下載的東西丟到Webroot目錄下即可,另外你可以可以直接改成
網上的一個下載鏈接~
我們都知道使用多線程下載文件可以更快地完成文件的下載,但是爲什麼呢?
答:因爲搶佔的服務器資源多,假設服務器最多服務100個用戶,服務器中的一個線程對應一個用戶
100條線程在計算機中併發執行,由CPU劃分時間片輪流執行,加入a有99條線程下載文件,那麼
相當於佔用了99個用戶資源,自然就有用較快的下載速度
ps:當然不是線程越多就越好,開啓過多線程的話,app需要維護和同步每條線程的開銷,這些開銷
反而會導致下載速度的降低,另外還和你的網速有關!
多線程下載的流程
獲取網絡連接——本地磁盤創建相同大小的空文件——計算每條線程需從文件哪個部分開始下載,結束
——依次創建,啓動多條線程來下載網絡資源的指定部分
ps:這裏直接用J2SE來完成多線程操作,直接建立一個工程,使用Junit運行指定方法即可
如果再Android下用單元測試有點麻煩,照顧一部分朋友,你直接new一個Java Project即可!
代碼如下:
DownLoader.java
- package com.jay.test;
- import java.io.InputStream;
- import java.io.RandomAccessFile;
- import java.net.HttpURLConnection;
- import java.net.URL;
- import org.junit.Test;
- public class Downloader {
- //添加@Test標記是表示該方法是Junit測試的方法,就可以直接運行該方法了
- @Test
- public void download() throws Exception
- {
- //設置URL的地址和下載後的文件名
- String filename = "meitu.exe";
- String path = "http://10.13.20.32:8080/Test/XiuXiu_Green.exe";
- URL url = new URL(path);
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
- conn.setConnectTimeout(5000);
- conn.setRequestMethod("GET");
- //獲得需要下載的文件的長度(大小)
- int filelength = conn.getContentLength();
- System.out.println("要下載的文件長度"+filelength);
- //生成一個大小相同的本地文件
- RandomAccessFile file = new RandomAccessFile(filename, "rwd");
- file.setLength(filelength);
- file.close();
- conn.disconnect();
- //設置有多少條線程下載
- int threadsize = 3;
- //計算每個線程下載的量
- int threadlength = filelength % 3 == 0 ? filelength/3:filelength+1;
- for(int i = 0;i < threadsize;i++)
- {
- //設置每條線程從哪個位置開始下載
- int startposition = i * threadlength;
- //從文件的什麼位置開始寫入數據
- RandomAccessFile threadfile = new RandomAccessFile(filename, "rwd");
- threadfile.seek(startposition);
- //啓動三條線程分別從startposition位置開始下載文件
- new DownLoadThread(i,startposition,threadfile,threadlength,path).start();
- }
- int quit = System.in.read();
- while('q' != quit)
- {
- Thread.sleep(2000);
- }
- }
- private class DownLoadThread extends Thread {
- private int threadid;
- private int startposition;
- private RandomAccessFile threadfile;
- private int threadlength;
- private String path;
- public DownLoadThread(int threadid, int startposition,
- RandomAccessFile threadfile, int threadlength, String path) {
- this.threadid = threadid;
- this.startposition = startposition;
- this.threadfile = threadfile;
- this.threadlength = threadlength;
- this.path = path;
- }
- public DownLoadThread() {}
- @Override
- public void run() {
- try
- {
- URL url = new URL(path);
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
- conn.setConnectTimeout(5000);
- conn.setRequestMethod("GET");
- //指定從什麼位置開始下載
- conn.setRequestProperty("Range", "bytes="+startposition+"-");
- //System.out.println(conn.getResponseCode());
- if(conn.getResponseCode() == 206)
- {
- InputStream is = conn.getInputStream();
- byte[] buffer = new byte[1024];
- int len = -1;
- int length = 0;
- while(length < threadlength && (len = is.read(buffer)) != -1)
- {
- threadfile.write(buffer,0,len);
- //計算累計下載的長度
- length += len;
- }
- threadfile.close();
- is.close();
- System.out.println("線程"+(threadid+1) + "已下載完成");
- }
- }catch(Exception ex){System.out.println("線程"+(threadid+1) + "下載出錯"+ ex);}
- }
- }
- }
運行截圖:
如圖,使用多線程完成了對文件的下載!雙擊exe文件可運行,說明文件並沒有損壞!
注意事項:
①int filelength = conn.getContentLength(); //獲得下載文件的長度(大小)
②RandomAccessFile file = new RandomAccessFile(filename, "rwd");
//該類運行對文件進行讀寫,是多線程下載的核心
③int threadlength = filelength % 3 == 0 ? filelength/3:filelength+1;
//計算每個線程要下載的量
④conn.setRequestProperty("Range", "bytes="+startposition+"-");
//指定從哪個位置開始讀寫,這個是URLConnection提供的方法
⑤//System.out.println(conn.getResponseCode());
//這個註釋了的代碼是用來查看conn的返回碼的,我們前面用的都是200,
而針對多線程的話,通常是206,必要時我們可以通過調用該方法查看返回碼!
⑥int quit = System.in.read();
while('q' != quit){Thread.sleep(2000);}
//這段代碼是做延時操作的,因爲我們用的是本地下載,可能該方法運行完了,而我們的
線程還沒有開啓,這樣會引發異常,這裏的話,讓用戶輸入一個字符,如果是'q'的話就退出
最後說兩句:
關於JavaIO中的File和RandowAccessFile就介紹這裏了,
大家可以發揮自己的創造力,使用這兩個類,實現自己想要的功能~
最後把File的東東都貼到一個工具類中,有需要的可以複製粘貼:
- import java.io.File;
- public class FileUtil {
- /*
- * 創建一個新文件
- * */
- public static void newFile(String fileName) throws Exception {
- File f = new File(fileName);
- f.createNewFile();
- }
- /*
- * 刪除文件
- * */
- public static void deleteFile(String fileName) {
- File f = new File(fileName);
- if (f.exists())
- f.delete();
- else
- System.out.println("文件不存在");
- }
- /*
- * 創建一個文件夾(目錄)
- * */
- public static void newDir(String fileName) {
- // fileName寫文件夾名哦,比如:D:\Test
- File f = new File(fileName);
- f.mkdir();
- }
- /*
- * 刪除一個文件夾(目錄)
- * */
- public static void deleteDir(File file) {
- File[] files = file.listFiles();
- for (File f : files) {
- if (f.isDirectory())// 遞歸調用
- {
- deleteDir(f);
- } else {
- f.delete();
- }
- }
- // 一層目錄下的內容都刪除以後,刪除掉這個文件夾
- file.delete();
- }
- /*
- * 判斷是否爲一個文件夾(目錄)
- * */
- public static boolean isDir(String fileName) {
- File f = new File(fileName);
- if (f.isDirectory()) {
- return true;
- }
- return false;
- }
- /*
- * 獲取目錄下的全部文件名,包含隱藏文件
- */
- public static void getAllFile1(String fileName) {
- File f = new File(fileName);
- String[] str = f.list();
- for (int i = 0; i < str.length; i++) {
- System.out.println(str[i]);
- }
- }
- /*
- * 獲取目錄下的全部文件名包含完整路徑,包含隱藏文件
- */
- public static void getAllFile2(String fileName) {
- File f = new File(fileName);
- File[] str = f.listFiles();
- for (int i = 0; i < str.length; i++) {
- System.out.println(str[i]);
- }
- }
- /*
- * 獲取某目錄下的全部文件(包含子目錄,完整路徑,隱藏文件)
- */
- public static void getAllFile3(File file) {
- if (file != null) {
- if (file.isDirectory()) {
- File[] fileArray = file.listFiles();
- if (fileArray != null) {
- for (int i = 0; i < fileArray.length; i++) {
- // 遞歸調用
- getAllFile3(fileArray[i]);
- }
- }
- } else {
- System.out.println(file);
- }
- }
- }
- /*
- * 遍歷某目錄下特定文件的文件名與路徑
- */
- public static void getSpecificFile(File file, String suffix) {
- if (file != null) {
- if (file.isDirectory()) {
- File[] fileArray = file.listFiles();
- String name1 = file.getName();
- System.out.println("——————" + name1);
- if (fileArray != null) {
- for (int i = 0; i < fileArray.length; i++) {
- // 遞歸調用
- getSpecificFile(fileArray[i], suffix);
- }
- }
- } else {
- if (file.getName().toString().endsWith(suffix)) {
- System.out.print(" ");
- System.out.println(file
- .getName()
- .toString()
- .substring(
- 0,
- file.getName().toString().length()
- - suffix.length()));
- }
- }
- }
- }
- /**
- * 批量修改文件名:
- * @param filename 要是目錄哦!
- */
- public static boolean changeFileNames(String fileName,String suffix)
- {
- File f = new File(fileName);
- if(!f.isDirectory())
- {
- return false;
- }
- int j = 0;
- File[] fs = f.listFiles();
- for(int i = 0;i < fs.length;i++)
- {
- String str = fs[i].getName();
- if(str.endsWith(suffix))
- {
- fs[i].renameTo(new File(fileName + File.separator +"head" + j +suffix));
- // System.out.println(fileName + File.separator +"head" + j +suffix);
- j++;
- }
- }
- return true;
- }
- }