1. File
- File類可以使用文件路徑字符串來創建File實例,該文件路徑可以是絕對路徑或相對路徑
- File類的list()方法中可以接收一個FilenameFilter參數,通過該參數可以只列出符合條件的文件
public class FileNameFilterTest { public void main(String[] args) { File file = new File("."); String[] nameList = file.list(((dir, name) -> name.endsWith(".java") || new File(name).isDirectory())); for (String name : nameList) { System.out.println(name); } } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
2. 流(Stream)
- Stream是從起源(source)到接收(sink)的有序數據
- 按照流向分可以分為輸入流和輸出流
- 輸入流:只能從中讀取數據,不能寫入數據(基類是InputStream和Reader)
- 輸出流:只能向其中寫入數據,不能讀取數據(基類是OutputStream和Writer)
- 按照操作的數據單元分為字節流和字符流
- 字節流:操作的數據單元是8位的字節(基類是InputStream和OutputStream)
- 字符流:操作的數據單元是16位的字節(基類時Reader和Writer)
- 按照角色可以分為節點流和處理流
- 節點流:可以從/向一個特定的IO設備中讀/寫數據的流,也被稱為低級流
- 處理流:用於對一個已存在的流進行連接或封裝來實現讀/寫功能,也稱為高級流或包裝流
3. 字節流和字符流
- 字節流輸入
public class FileInputStreamTest { public void main(String[] args) throws IOException { FileInputStream fis = new FileInputStream("FileInputStreamTest.java"); byte[] bytes = new byte[1024]; int hasRead = 0; while ((hasRead = fis.read(bytes)) > 0) { System.out.println(new String(bytes,0,hasRead)); } fis.close(); } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 字節流輸出
public class FileOutputStreamTest { public void main(String[] args) { try (FileOutputStream fileOutputStream = new FileOutputStream("file.txt"); FileInputStream fileInputStream = new FileInputStream("FileInputStreamTest.java")) { byte[] bytes = new byte[1024]; int hasRead = 0; while ((hasRead = fileInputStream.read(bytes)) > 0) { fileOutputStream.write(bytes,0,hasRead); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 字符流輸入
public class FileReaderTest { public void main(String[] args) { try (FileReader fileReader = new FileReader("FileInputStreamTest.java")) { char[] chars = new char[1024]; int hasRead = 0; while ((hasRead = fileReader.read(chars)) > 0) { System.out.println(new String(chars,0,hasRead)); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 字符流輸出
public class FileWriterTest { public void main(String[] args) { try (FileWriter fileWriter = new FileWriter("poem.txt")){ fileWriter.write("錦瑟 -李商隱\r\n");// \r\n時windows平台的換行符 fileWriter.write("錦瑟無端五十弦,一弦一柱思華年\r\n"); fileWriter.write("庄生曉夢迷蝴蝶,望帝春心托杜鵑\r\n"); fileWriter.write("滄海月明珠有淚,藍田日暖玉生煙\r\n"); fileWriter.write("此情可待成追憶,只是當時已惘然\r\n"); } catch (IOException e) { e.printStackTrace(); } } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
4. 處理流/轉換流
- 構造器參數不是一個物理節點,而是已經存在的流
- 關閉最上層的流時,會自動關閉被該處理流包裝的節點流
- 如果進行輸入/輸出的是文本內容,應當考慮字符流,如果進行輸入/輸出的內容時二進制內容,則應該考慮使用字節流
- 轉換流用於實現將字節流轉換成字符流,InputStreamReader將字節輸入流轉換成字符輸入流;OutputStreamWriter將字節輸出流轉換成字符輸出流
- BufferReader流具有緩沖功能
5. 重定向標准輸入/輸出
- 重定向是指改變輸入/輸出目標(由鍵盤/屏幕改為文件)
- 重定向輸出流
public class RedirectOut { public void main(String[] args) { try (PrintStream printStream = new PrintStream(new FileOutputStream("out.txt"))){ System.setOut(printStream); System.out.println("普通字符串"); System.out.println(new RedirectOut()); } catch (FileNotFoundException e) { e.printStackTrace(); } } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 重定向輸入流
public class RedirectIn { public void main(String[] args) { try (FileInputStream fileInputStream = new FileInputStream("poem.txt")) { System.setIn(fileInputStream); Scanner scanner = new Scanner(System.in); scanner.useDelimiter("\n");//只把回車作為換行符 while (scanner.hasNext()) { System.out.println("鍵盤輸入內容:" + scanner.next()); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
6. RandomAccessFile
- RandomAccessFile支持任意訪問,可以直接調整到文件的任意地方讀寫數據
- 可以向已存在的文件后追加內容
- 只能讀寫文件,不能讀寫其他IO節點
- 包含一個記錄指針,用以標識當前讀寫處的位置
- 直接將文件記錄指針移動到中間某位置后進行輸出會覆蓋原有的內容
- 讀取文件
public class RandomAccessFileTest { public void main(String[] args) { try (RandomAccessFile randomAccessFile = new RandomAccessFile("poem.txt", "r")) { System.out.println("指針初始位置:" + randomAccessFile.getFilePointer()); randomAccessFile.seek(300); byte[] buffer = new byte[1024]; int hasRead = 0; while ((hasRead = randomAccessFile.read(buffer)) > 0) { System.out.println(new String(buffer, 0, hasRead)); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 向文件末尾追加內容
public class AppendContent { public void main(String[] args) { try (RandomAccessFile randomAccessFile = new RandomAccessFile("poem.txt", "rw")) { randomAccessFile.seek(randomAccessFile.length()); randomAccessFile.write("追加的內容!\n".getBytes()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 向指定位置添加內容
public class InsertContent { public void main(String[] args) throws IOException { File file = File.createTempFile("tmp", null); file.deleteOnExit(); try (RandomAccessFile randomAccessFile = new RandomAccessFile("poem.txt", "rw"); FileOutputStream tmpOut = new FileOutputStream(file); FileInputStream tmpIn = new FileInputStream(file)) { randomAccessFile.seek(300); //將文件內容寫入臨時文件中 byte[] buffer = new byte[64]; int hasRead = 0; while ((hasRead = randomAccessFile.read(buffer)) > 0) { tmpOut.write(buffer, 0, hasRead); } randomAccessFile.seek(300); randomAccessFile.write("插入的內容".getBytes()); //追加之前的內容 while ((hasRead = tmpIn.read(buffer)) > 0) { randomAccessFile.write(buffer, 0, hasRead); } } } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
7. 對象序列化
- 對象序列化(Serialize)是指將一個Java對象寫入IO流中
- 對象反序列化(Deserialize)是指從IO流中恢復該Java對象
- 序列化必須實現Serializable和Externalizable接口
- 序列化
public class WriteObject { public void test() { try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("object.txt"))) { Person person = new Person("HelloWood", 22); Person person1 = new Person("HoloWood", 33); objectOutputStream.writeObject(person); objectOutputStream.writeObject(person1); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 反序列化
public class ReadObject { public void test() { try (ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("object.txt"))) { Person p = (Person) objectInputStream.readObject(); Person p1 = (Person) objectInputStream.readObject(); System.out.println(p.getName() + " " + p.getAge()); System.out.println(p1.getName() + " " + p1.getAge()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 反序列化時讀取的僅僅時Java對象的數據,而不是Java類
- 反序列化無須通過構造器來初始化Java對象
- 如果序列化時寫入多個對象,則反序列化時必須按實際寫入順序讀取
- 當一個可序列化類有父類時,這些父類必須時可序列化的
- 當某個類的成員變量的類型不是基本類型或String類型而是引用類型時,這個引用類型必須也是可序列化的
- 多次序列化同一個Java對象時,只有第一次序列化時才會把該Java對象轉換成字節序列並輸出
- 當序列化某個對象后修改該對象的屬性再序列化不會將修改后的屬性輸出
- 當對某個對象進行序列化時,系統會自動把該對象的所有實例變量依次進行序列化
- 如果在實例變量前用transient修飾,則該變量在實例化時會自動跳過
- 如果重寫了writeReplace()方法,則在序列化時會先調用該方法進行替換
8. NIO(New IO)
- NIO采用內存映射的方式來處理輸入輸出,通過將文件或部分文件的一段區域映射到內存中進行訪問
- NIO中的所有數據都需要通過通道(Channel)傳輸
- 傳統IO面向流處理,NIO面向塊處理
Buffer本質是一個數組
- 容量(capacity):可以最大存儲的數據量,不能為負值,創建后不可改變
- 界限(limit):第一個不應該被讀出或者寫入的緩沖區位置索引,limit后的數據不能被讀寫
- 位置(position):用於指明下一個可以被讀出的或者寫入的緩沖區位置索引
- 標記(mark):標記,用於自定義記錄位置
- 0 <= mark <= position <= limit <= capacity
- flip()方法將limit設置為position所在位置,將position置為0,為讀取數據做准備
- clear()將position置為0,limit置為capacity,但不清空數據,為再次裝入數據做准備
Channel
- 只能和Buffer交互
- Channel應當通過XXXStream.getChannel()方法獲取
public class ReadFile { public void test() { try (FileInputStream fileInputStream = new FileInputStream("poem.txt"); FileChannel fileChannel = fileInputStream.getChannel()) { ByteBuffer byteBuffer = ByteBuffer.allocate(256); while (fileChannel.read(byteBuffer) != -1) { byteBuffer.flip(); Charset charset = Charset.forName("UTF-8"); CharsetDecoder charsetDecoder = charset.newDecoder(); CharBuffer charBuffer = charsetDecoder.decode(byteBuffer); System.out.println(charBuffer); byteBuffer.clear(); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
9. 文件鎖
- lock()鎖定文件時如果無法得到文件鎖,程序就會一直阻塞
- tryLock()鎖定文件時如果獲得了文件鎖,則會返回文件鎖,否則返回null
- tryLock(long position,long size,boolean shared)
- 當shared為true時,該鎖是共享鎖,將允許多個進程讀取該文件
- 當shared為false時,該鎖時排他鎖,將鎖住對該文件的讀寫
- 通過FileLock的release()方法釋放文件鎖
- 文件鎖時Java虛擬機所持有的
public class FileLockTest { public void test() { try (FileChannel fileChannel = new FileOutputStream("poem.txt").getChannel()){ FileLock lock = fileChannel.tryLock(); Thread.sleep(10000); lock.release(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
10. NIO2
- 使用FileVisitor遍歷文件和目錄
public class FileVisitorTest { public void test() throws IOException { Files.walkFileTree(Paths.get("/","home"),new SimpleFileVisitor<Path>(){ @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { System.out.println("正在訪問:"+file+"文件"); if (file.endsWith("poem.txt")) { System.out.println("---已經找到目標文件---"); System.out.println("文件目錄:"+file); return FileVisitResult.TERMINATE; } return FileVisitResult.CONTINUE; } @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { System.out.println("正在訪問:"+dir+"路徑"); return FileVisitResult.CONTINUE; } }); } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 使用WatchService監控文件變化
public class WatchServiceTest { public void test() { WatchService watchService = null; try { watchService = FileSystems.getDefault().newWatchService(); Paths.get("/home/alpha/IdeaProjects/out/production/IdeaProjects/").register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_DELETE); while (true) { WatchKey key = watchService.take(); for (WatchEvent<?> event : key.pollEvents()) { System.out.println(event.context() + "發生了" + event.kind() + "事件"); } boolean valid = key.reset(); if (!valid) { break; } } } catch (InterruptedException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }