JavaEEDay19-文件操作

JavaEEDay19-文件操作

一、複習:泛型

  • 爲了解決數據類型一致化問題,避免沒有意義的強制類型轉換(放進什麼數據,拿出來什麼數據),控制輸入數據的格式;

  • 定義泛型泛型使用的格式:
    <大寫字母> 一般使用E 或者 T ,僅僅是佔位符;

(一)泛型函數中使用

格式:

權限修飾符 <自定義泛型> 返回值類型(可以使用泛型) 函數名(形式參數列表“自定義泛型”) {
  同樣可以使用自定義泛型
}

(二)泛型在類中使用

格式:

class 類名<自定義泛型> {
  非靜態的成員變量或者成員方法都可以使用類中定義的<自定義泛型>;  
  靜態方法不能使用類中自定義泛型,但是可以方法中自己定義泛型;  
}

例如:Arrays.sort(T[] t, Comparator<? super T> c)

(三)泛型在接口中使用

格式:

interface 接口名<自定義泛型> {
  //成員變量 缺省屬性:public static final
  //成員方法 缺省屬性:abstract
}
  • 一個類遵從帶有自定義泛型的接口有兩種方式:
    例如接口如下:
    interface A {
    public void testA(T t);
    }
  1. 方式1:更加自由,在創建類對象時,纔對泛型進行約束
class Test1<T> implements A<T> {
  public void testA(T t) {
      //實現方法
  }
}
  1. 方式2 :遵從接口時,接口直接確定了泛型的具體類型
class Test2 implements A<String> {
  public void testA(String t) {
      //實現方法
  }
}
  • 泛型的上下限:
    <? super T> 表示數據類型是T對象或者其父類對象
    <? extends T>表示數據類型是T對象或者其子類對象

Map

Map<K, V> 鍵值對

  • 兩個實現類:

    • HashMap
    • TreeMap
  • 常見的方法:

put(K key , V value);
putAll(Map<? extends k, ? extends V> map)

clear();
remove(Object k);

size();
containsKey(Object key);
containsValue(Object Value);

keySet();
values();

get(Object k);

簡單介紹了一個匿名內部類

 new Comparator<Student>() {
      @Override   
      public int compare(Student o1, Student o2) {
          return o1.getAge() - o2.getAge();
      }
  }

Map 補充

package study;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;

public class Demo1 {
	public static void main(String[] args) {
		HashMap<String, Integer> map = new HashMap<String, Integer>();
		
		map.put("MacBook Pro", 22888);
		map.put("iPhoneX", 8398);
		map.put("iPad Pro", 5198);
		
		System.out.println(map);
		
		//第一種遍歷方式:藉助於keySet,通過key值拿到value值
		Set<String> set = map.keySet();
		
		//使用Set集合的Iterator迭代器
		Iterator<String> it = set.iterator();
		while (it.hasNext()) {
			String key = it.next(); //獲取每一個Map中的key值
			int value = map.get(key);
			
			System.out.println(key + "=" + value);
		}
		//以上方法,不太合適,實際上獲取的key值,再借助於Map裏面的get方法,獲取對應的Value
		//實際上並沒有獲取到完整的鍵值對
		
		
		
		//第二種方式:藉助於values
		Collection<Integer> c = map.values();
		
		for (Integer integer : c) {
			System.out.println(integer);
		}
		
		//以上方法也不適合,因爲只能拿到value值,獲取不到對應的key
		
		
		
		//在Java中萬物皆對象,因此可以將鍵值對看成是一個類【必須會】
		/*
	 	將鍵值對,認爲是一個對象,組成一個類,稱之爲Entry
		 class Entry<K, V> {
		 	K key;
		 	V value;
		 } 
		 這裏可以認爲在Map集合中,保存的每個鍵值對都是一個Entry對象
		 將這些Entry對象獲取並做成一個集合,然後對該集合進行遍歷;
		 entrySet();
		 Map.Entry;Entry爲Map的子接口,稱爲內部類
		 */
		Set<Entry<String, Integer>> entrySet = map.entrySet();
		
		Iterator<Entry<String, Integer>> it2 = entrySet.iterator();
		
		while (it2.hasNext()) {
			System.out.println(it2.next());
		}
	}
}

文件操作

IO:
Input Output
read write

只考慮文件操作情況下:

  • 讀取操作是:input read 從硬盤(存儲設備) 到 內存
  • 寫入操作是:output write 從內存 到 硬盤(存儲設備)

如何操作文件或者文件夾:
創建,刪除,剪切,複製,重命名,粘貼

Java裏萬物皆對象,計算機世界裏萬物皆文件

  • Sun提供了一個File類,專門來操作【文件】和【文件夾】
 如何創建一個File類對象:
File(String pathName);
根據文件路徑創建File類對象,可以是【絕對路徑】可以是【相對路徑】

File(String parent, String child);
根據提供的父目錄【文件夾】地址,和當前文件夾下的【子文件】或者【子文件夾】創建File類對象

File(File parent, String child);
根據創建好的父目錄的File類對象,和這個目錄下的【子文件】或者【子文件夾】創建File類對象

【pathName】
\n \t \ 轉義字符
假如實際地址爲:C:\aaa\bbb 如果在代碼中使用 “C:\aaa\bbb” LOW

推薦使用 /來區分路徑,不使用反斜槓
Java是一個跨平臺的語言
Java提供了一個系統變量:File.separator 可以根據不同的系統換,自動填充文件分隔符
示例:

public class Demo1 {
	public static void main(String[] args) {
		File file1 = new File("C:\\aaa"); //採用Windows的分隔符
		File file2 = new File("C:/aaa"); //用在Linux和Windows通用的分隔符
		File file3 = new File("C:" + File.separator + "aaa"); //這裏使用Java系統變量
		
		System.out.println(file1);
		System.out.println(file2);
		System.out.println(file3);
		
		File file4 = new File("C:\\aaa", "1.txt"); //父目錄 子目錄 
		System.out.println(file4); //返回的是路徑
		
		File file5 = new File(file1, "1.txt");
		System.out.println(file5);
	}
}

File 操作常見方法:

isFile(); //是否爲文件
isDirectory(); //是否爲目錄
createFile()
renameTo
copy

可以利用File類對象,創建文件或者文件夾

  • boolean createNewFile(); 創建文件
    使用File類對象,創建File類對象裏面保存的地址 指定 的 普通文件
    返回值boolean: 創建成功返回true,創建失敗返回false
    返回false失敗原因:
    1. 該文件已經存在
    2. 操作路徑非法,例如:文件指定所在文件夾不存在
    3. 操作的文件夾沒有寫入權限
    4. 硬盤壞了
    【要求】
    創建文件,必須帶有文件後綴名!!!
    .java .class .doc .txt .xml .html .css .js .md .jsp
    .m .h .c .cpp .php .net .ppt .xls .exe .zip .rar .mp4
    .rmvb

  • boolean mkdir(); make direcotry 創建文件夾
    使用File類對象裏面保存的文件夾地址,創建對應的文件夾

    • 返回值:boolean 創建成功返回true 創建失敗返回false
    • 失敗原因:
      1. 已經存在該文件夾
      2. 指定創建文件夾的父目錄沒有寫入權限
      3. 要創建文件夾的父目錄不存在
  • boolean mkdirs();
    使用File類對象裏面保存的文件夾路徑地址,創建指定文件夾,如果該路徑中的【中間文件夾】不存在,把中間路徑,同時創建

    • 返回值:boolean 創建成功返回true 創建失敗返回false
    • 失敗原因:
      1. 已經存在該文件夾
      2. 指定創建文件夾沒有寫入權限
        C:/aaa/ccc/ddd/eee/fff/ggg/hhh/iii/jjj
  • boolean renameTo(File dest);

    • 功能1:
      重命名!!!文件 或者 文件夾
    • 功能2:
      剪切,移動到另一個位置

    作業:
    測試,renameTo操作一個非空文件夾!!!

程序測試:

import java.io.File;
import java.io.IOException;

public class Demo2 {
	public static void main(String[] args) throws IOException {
		
		//創建文件
		File file1 = new File("C:/aaa/1.txt");
		
		boolean ret = file1.createNewFile();
		System.out.println("文件創建成功了嗎?" + ret);
		
//		File file2 = new File("C:/bb/1.txt");
//		System.out.println(file2.createNewFile());
		
		File file2 = new File("C:/aaa/bbb");
		ret = file2.mkdir();
		System.out.println("文件夾創建成功了嗎?" + ret);
		
		File file3 = new File("C:/aaa/ccc/ddd");
		ret = file3.mkdir();
		System.out.println("文件夾創建成功了嗎?" + ret);
		
		File file4 = new File("C:/aaa/ccc/ddd/eee/fff/ggg/hhh/iii/jjj");
		ret = file4.mkdirs();
		System.out.println("文件夾創建成功了嗎?" + ret);
		
		
		File dest1 = new File("C:/aaa/2.txt");
		//把C:/aaa/1.txt 重命名!!!
		ret = file1.renameTo(dest1); //裏面的參數爲命名文件的新抽象路徑名稱,因爲要求File類型,不能使用字符串路徑;
		System.out.println("重命名成功了嗎?" + ret);
		
		ret = file2.renameTo(new File("C:/aaa/ddd")); //需要將路徑創建爲一個新的File類對象
		System.out.println("重命名文件夾成功了嗎?" + ret);
		
		//測試剪切功能
		//原地址要帶有文件或者文件夾名,而且目標地址也有帶有文件或者文件夾名
		File txt3 = new File("C:/aaa/3.txt");
		File dest2 = new File("C:/Users/劉曉磊/Desktop/3.txt");
		
		ret = txt3.renameTo(dest2);
		System.out.println("剪切成功了嗎?" + ret);
		
	}
}
  • delete()
    刪除文件或者文件夾,但是如果操作文件夾的話,只能刪除空文件夾,成功返回true ,失敗返回false;
    該刪除操作不是把文件或者文件夾放入到回收站裏,而是直接從磁盤上抹去數據,該操作不可逆

  • deleteOnExit()
    當JVM虛擬機運行終止之後,刪除指定的文件或者文件夾,而不是調用立即刪除;

    • 用途:
      用於刪除程序運行結束之後殘留的緩存文件或者運行日誌文件,節約硬盤空間;

代碼示例:

import java.io.File;
import java.util.Scanner;
public class Demo3 {
	public static void main(String[] args) {
		File file1 = new File("C:/aaa/1.txt");
		
		System.out.println("刪除成功了嗎?" + file1.delete());
		
		File file2 = new File("C:/aaa/ddd");
		System.out.println("刪除成功了嗎?" + file2.delete());
		
		File file3 = new File("C:/aaa/ccc");
		System.out.println("刪除成功了嗎?" + file3.delete()); //返回false
		
		// deleteOnExit()使用方法
		File file4 = new File("C:/aaa/2.txt");
		Scanner sc = new Scanner(System.in);
		
		file4.deleteOnExit();
		sc.nextLine();
	}
}
  • exists(); 判斷指定的文件或者文件夾是否存在
  • isFile(); 判斷指定的File是文件嗎?
  • isDirectory(); 判斷指定的File是文件夾嗎?
  • isHidden(); 判斷指定的File是隱藏文件嗎?
  • isAbsolute(); 判斷創建File類對象使用的是絕對路徑嗎?
    返回值全是boolean

代碼示例:

import java.io.File;
public class Demo4 {
	public static void main(String[] args) {
		File file = new File("C:/aaa/1.txt");
		
		System.out.println("這個文件或者文件夾存在嗎?" + file.exists());
		System.out.println("這個File類對象是一個文件類對象嗎?" + file.isFile());
		//這裏使用了匿名對象,我一般稱之爲 一點到底!!!
		System.out.println("這個File類對象是一個文件夾類對象嗎?" + new File("C:/aaa").isDirectory());
		System.out.println("這個File類對象是一個隱藏文件對象嗎?" + file.isHidden());
		System.out.println("創建File類對象使用了絕對路徑嗎?" + file.isAbsolute());
		System.out.println("創建File類對象使用了絕對路徑嗎?" + new File(".").isAbsolute()); //. 表示當前目錄		
	
	}
}

以下方法和文件是否【存在無關】!!!!!!

  • getName(); 獲取路徑中的文件名或者文件夾名

  • getPath(); 獲取File類對象裏面保存的路徑

  • getAbsolutePath(); 獲取File對象裏面保存路徑對應的絕對路徑

  • getParent(); 獲取當前文件或者文件夾的父目錄,如果沒有返回null

  • lashModified(); 文件最後的修改時間
    UNIX時間戳
    計算機元年到修改時間的秒數:
    1970年01月01日 00:00:00
    2017年12月08日 15:24:50

  • length(); 文件的大小(字節數),如果文件不存在,或者是一個文件夾,返回0L

代碼示例:

import java.io.File;
import java.sql.Date;
import java.text.SimpleDateFormat;
public class Demo5 {
	public static void main(String[] args) {
		File file = new File("E:/aaa/1.txt");
	
		System.out.println(file.getName()); //1.txt
		System.out.println(file.getPath()); //E:/aaa/1.txt
		System.out.println(file.getAbsolutePath()); //E:/aaa/1.txt
		System.out.println(file.getParent()); //E:/aaa
		
		long last = new File("C:/aaa/1.txt").lastModified();
		
		Date date = new Date(last);
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		System.out.println(format.format(date));
		
		//System.out.println(last); //直接使用這個會得到秒數
	}
}

其他方法:返回值 方法 含義

  • static File[] listRoots();
    獲取當前計算機中所有的盤符,針對Windows操作系統
    Linux/UNIX沒有區分盤符的概念 只有一個根目錄 /

  • String[] list();
    獲取指定【文件夾】裏面所有子文件和子文件,返回一個String類型的的數組

  • File[] listFiles();
    獲取指定【文件夾】裏面所有子文件和子文件,返回一個File類型的的數組

  • 遍歷一個文件夾:
    文件夾:
    文件夾1;
    文件夾2;
    文件夾3;
    ………………
    文件:
    文件1;
    文件2;
    文件3;
    ………………

代碼示例:

import java.io.File;
public class Demo6 {
	public static void main(String[] args) {
		File[] roots = File.listRoots();
		for (File file : roots) {
			System.out.println(file.getPath());
		}
		System.out.println("---------------------------------");
		
		File file = new File("C:\\Program Files\\Java\\jdk1.8.0_131");
		String[] allFilePath = file.list();
		
		for (String string : allFilePath) {
			System.out.println(string);
		}
		
		System.out.println("---------------------------------");
		
		File[] allFileObject = file.listFiles();
		for (File file2 : allFileObject) {
			System.out.println(file2);
		}
		
	}
}
  • 遍歷一個文件夾:
    文件夾:
    文件夾1;
    文件夾2;
    文件夾3;
    ………………
    文件:
    文件1;
    文件2;
    文件3;
    ………………
  1. 首先利用listFiles()方法,獲取指定文件夾下的所有子文件和子文件夾的File類對象數組
  2. 利用isFile或者isDirectory判斷是否是文件或者是文件夾
  3. 區別對象,利用不同的函數

找出指定文件夾下的所有.java文件? endWith() 和 isFile()

public class Demo7 {
	public static void main(String[] args) throws FileNotFoundException {
		
		findAllJavaFile("C:\\Users\\劉曉磊\\Desktop\\test");
		
		File srcDir = new File("C:\\Program Files\\Java\\jdk1.8.0_131");
		
		if (srcDir.exists() && srcDir.isDirectory()) {
			
			File[] allFiles = srcDir.listFiles();
			
			showAllFiles(allFiles);
			showAllDirectories(allFiles);
		} 
	}
	
	private static void showAllFiles(File[] allFiles) {
		System.out.println("普通文件:");
		for (File file : allFiles) {
			if (file.isFile()) {
				System.out.println("\t" + file.getName());
			}
		}
	}
	
	private static void showAllDirectories(File[] allFiles) {
		System.out.println("文件夾:");
		for (File file : allFiles) {
			if (file.isDirectory()) {
				System.out.println("\t" + file.getName());
			}
		}
	}
	
	public static void findAllJavaFile(String pathname) throws FileNotFoundException {
		//如果給定的路徑是一個null,無法使用
		if (null == pathname) {
			throw new NullPointerException();
		}
		
		File srcDir = new File(pathname);
		
		//判斷文件是否存在,是否是一個文件夾
		if (!srcDir.exists()) { //srcDir.exists() == false
			throw new FileNotFoundException();
		} else if (!srcDir.isDirectory()) { //srcDir.isDirectory() == false
			//運行時異常,不用再函數中聲明
			throw new RuntimeException("該文件不是一個文件夾");
		}
			
		File[] allFiles = srcDir.listFiles();
		
		for (File file : allFiles) {
			//文件名後綴爲.java 並且 是一個普通文件
			if (file.getName().endsWith(".java") && file.isFile()) {
				System.out.println(file.getName());
			}
		}
	
	} 
}


  • 歸檔文件

如果是普通文件,按照文件的後綴名創建對應的全大寫文件夾,把文件剪切進去
特殊情況,如果是沒有文件後綴名的未知普通文件,就放入到 others 文件夾;
如果是文件夾,創建 subDir 文件夾,剪切進去;

  • 思路:
    • 1.獲取指定的文件夾路徑,進行判斷;
    • 2.獲取這個文件夾下面的所有子文件和子文件夾的 File[]類對象;
    • 3.遍歷這個 File[] 類型的數組,按照文件和文件夾進行區別操作;
      • 3.1.如果是文件:
        • 首先獲取這個文件的文件後綴;
        • 然後創建以這個文件後綴名全大寫的文件夾;
        • 最後移動該文件到這個文件夾;
        • 注:如果一個文件沒有後綴名,就放入到 Others 目錄下;
      • 3.2.如果是文件夾:
        • 首先創建 subDir 目錄;
        • 移動該文件夾放入到 subDir 裏面;

程序代碼:

package study;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

public class Demo1 {
	public static void main(String[] args)throws NullPointerException, IOException {
		achieveDirectoryAtPath("C:/test");
	}
	
	public static void achieveDirectoryAtPath(String path) throws NullPointerException, IOException{
		//1.判斷路徑
		if (null == path) {
			throw new NullPointerException("地址不能爲null");
		}
		
		//2.創建指定地址對應的File類對象
		File file = new File(path);
		
		//3.判斷這個是不是一個文件夾,並且是否存在
		if ((!file.exists() || !file.isDirectory())) {
			//等價於:file.exists() == false || file.isDirectory() == false;
			throw new FileNotFoundException("沒有指定文件");
		}
		
		//在歸檔之前判斷是否進行過歸檔操作,如果有則不再進行歸檔
		if (new File(file, "file.lock").exists()) {
			System.out.println("歸檔已完成");
			return ;
		}
		
		//4.獲取指定文件夾下面的所有子文件和子文件夾的File類對象數組
		File[] allFiles = file.listFiles();
		
		//5.遍歷該File數組,判斷是文件還是文件夾,區別對待
		for (File fileItem : allFiles) {
			if (fileItem.isFile()) {
				//文件操作file是當前要歸檔的文件夾,filename是要處理的文件名字
				achieveFile(file,fileItem.getName());
			}else {
				//文件夾操作
				achieveDri(file, fileItem.getName());
			}
		}//for	
		
		//6.歸檔完成,上鎖,防止再次歸檔
		File lockFile = new File(file, "file.lock");
		lockFile.createNewFile();
	}
	

	
	private static void achieveFile(File file, String fileName) {
		//1.找到對應的文件後綴名
		int index = -1;
		String dirToCreate = null;
		File srcFile = null; //原地址 
		File dstFile = null;
		
		//2.獲取要創建的文件夾路徑的String類型字符串
		//判斷文件是否存在文件後綴名,如果沒有'.'則是不存在,有點但是點後面沒有內容也是沒有後綴名
		if ((index = fileName.lastIndexOf('.')) != -1 && fileName.substring(index + 1).length() !=0) { //不能包括index,因此加1
			/*上面的If語句等價於下面
			 * index = fileName.lastIndexOf('.');
			if (index != -1) {				
			}
			*/
			
			 /*
			String parent = file.getAbsolutePath();
			String dirName = fileName.substring(index + 1).toUpperCase();
			dirToCreate = parent + File.separator + dirName;
			*/
			//上面代碼的簡化版
			/*
			 * File.separator作用:這是File類提供的一個更加運行環境而決定的文件路徑分隔符,在Windows中是\,
			 * 在Linux和Unix中是/,這樣寫的好處是可以讓代碼的通用性和可移植性更好
			 */
			dirToCreate =file.getAbsolutePath() + file.separator + fileName.substring(index + 1).toUpperCase();			
		}else {
			dirToCreate = file.getAbsolutePath() + file.separator + "other";
		}
		
		new File(dirToCreate).mkdir();  //創建File匿名對象,調用mkdir()
		
		srcFile = new File(file, fileName);
		dstFile = new File(dirToCreate,fileName);
		
		srcFile.renameTo(dstFile);
	}
	 
	private static void achieveDri(File file, String dirName) {
		//創建subDir
		File subDir = new File(file, "subDir");
		subDir.mkdir();
		
		File srcFile = new File(file, dirName);
		File dstFile = new File(subDir, dirName);
		
		srcFile.renameTo(dstFile);
	}
}

單例

目的:使整個程序的運行過程中,有且只有一個當前類的類對象存在;

方案一:在整個程序的運行過程中,有且只調用一個構造方法(相當於僅僅實例化一次)
缺點:第三方調用者不知道這個規定,可以通過簡單的 new 關鍵字進行調用;
同時如果使用 private 關鍵字修飾構造函數,則構造方法在類外無法使用且類外沒有對象,則所有和對象相關的方法均不能使用,需要不通過對象就可以調用方法:
使用 static 關鍵字獲取或者創建類對象

  • 該方法提供給類外使用,因此權限修飾符爲【public】
  • 調用時候不能通過類對象進行調用,需要類名進行調用,使用【static】關鍵字
  • 該方法是獲取當前類的類對象,所以返回值應該是當前類對象類型
  • 方法名稱:【getInstance()】
  • 參數要和類內私有化的構造方法所需要的參數一致:【int num】

但是仍然需要判斷一下當前程序中有沒有已經創建的類對象,如果沒有就調用私有化的構造方法進行創建,否則不再創建;
這裏需要一個當前類的數據類型來保存這個變量,該變量保存已經創建對象的地址。

  • 因爲函數局部變量的生存期只有在這個方法內部,第二次再次調用的時候,之前的局部變量已經銷燬;
  • 同時因爲這是靜態方法,不能使用非靜態的成員變量,只能使用靜態成員變量;
package study;

class Demo{
	int num;
	private static Demo demo = null; //不能在類外更改,防止再次初始化
	
	private Demo(int num) {
		this.num = num;
	}
	
	public void test() {
		System.out.println(this.getClass() + "的test方法");
	}
	
	public static Demo getInstance(int  num) {
		//判斷是否已經創建類對象		
		if (demo == null) {
			demo = new Demo(num);
		}
		//私有化的構造方法可以在類內使用
		return demo;
	}
}


public class SingleDemo {
	public static void main(String[] args) {
		//Demo1 demo1 = new Demo1(3);
		
		Demo demo1 = Demo.getInstance(3);
		Demo demo2 = Demo.getInstance(4);
		System.out.println(demo1);
		System.out.println(demo2);
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章