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:更加自由,在創建類對象時,纔對泛型進行約束
class Test1<T> implements A<T> {
public void testA(T t) {
//實現方法
}
}
- 方式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
- 失敗原因:
- 已經存在該文件夾
- 指定創建文件夾的父目錄沒有寫入權限
- 要創建文件夾的父目錄不存在
-
boolean mkdirs();
使用File類對象裏面保存的文件夾路徑地址,創建指定文件夾,如果該路徑中的【中間文件夾】不存在,把中間路徑,同時創建- 返回值:boolean 創建成功返回true 創建失敗返回false
- 失敗原因:
- 已經存在該文件夾
- 指定創建文件夾沒有寫入權限
C:/aaa/ccc/ddd/eee/fff/ggg/hhh/iii/jjj
-
boolean renameTo(File dest);
- 功能1:
重命名!!!文件 或者 文件夾 - 功能2:
剪切,移動到另一個位置
作業:
測試,renameTo操作一個非空文件夾!!! - 功能1:
程序測試:
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;
………………
- 首先利用listFiles()方法,獲取指定文件夾下的所有子文件和子文件夾的File類對象數組
- 利用isFile或者isDirectory判斷是否是文件或者是文件夾
- 區別對象,利用不同的函數
找出指定文件夾下的所有.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 裏面;
- 3.1.如果是文件:
程序代碼:
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);
}
}