title: java IO
date: 2018-12-16 15:54:20
updated: 2020-03-15 16:11:45
categories: java
tags:
- java
此文檔爲java IO的學習總結
文件輸入與輸出
- 1.從文件中讀取信息
//從文件中讀取數據信息並打印輸出
import java.io.IOException;
import java.nio.file.Paths;
import java.util.Scanner; //三個包不能少
public class Test {
public static void main(String args[]) throws IOException //這個throws不能少
{
Scanner in = new Scanner(Paths.get("d:\\1.txt"));
String data = in.nextLine();
String data2 = in.nextLine();
System.out.println(data + '\n' + data2);
}
}
- 2.寫入數據信息到文件中
//向文件中寫入數據信息
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Scanner; //三個包不能少
public class Test {
public static void main(String args[]) throws IOException //這個throws不能少
{
PrintWriter out = new PrintWriter("d:\\2.txt");
out.println("hahahaha"); //寫入數據信息到指定文件
out.flush(); //刷新文件
}
}
Java IO: 管道
由於java語言的stream嚴格區分爲inputstream和outputstream,流數據讀寫之間轉換一般使用臨時文件方式來轉換,但是這種方式使用的效率比較低,因此可以使用管道來實現,java管道支持比較弱,需要多線程來支持,
import org.junit.Test;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
/**
* FileName: TestPipe
* Author: braincao
* Date: 2018/10/4 15:23
* Description: 兩個線程間用管道實現通信的例子
* Java IO中的管道爲運行在同一個JVM中的兩個線程提供了通信的能力
*/
public class TestPipe {
@Test
public void test1() throws IOException{
PipedOutputStream output = new PipedOutputStream();
PipedInputStream input = new PipedInputStream(output);
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
try{
output.write("hello world".getBytes());
output.close(); //通信完切記關閉管道資源
}catch(IOException e){
e.printStackTrace();
}
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
try{
int data = input.read();
while(data!=-1){
System.out.print((char)data + " ");
data = input.read();
}
input.close();//通信完切記關閉管道資源
}catch(IOException e){
e.printStackTrace();
}
}
});
thread1.start();
thread2.start();
}
}
//out:h e l l o w o r l d
java IO
1.File類: 文件或目錄路徑(文件夾)的抽象表示形式。通過File對象可以訪問文件的屬性、創建空文件和目錄
@Test
public void test1() throws IOException, InterruptedException{
//創建目錄路徑(文件夾)--mkdir():如果父目錄不存在,失敗
String path2 = "/Users/braincao/git/test";
File file2 = new File(path2);
boolean flag = file2.mkdir();
System.out.println(flag);
//創建目錄路徑(文件夾)--mkdirs():如果父目錄不存在,一同創建
String path = "/Users/braincao/git/test/test";
File file3 = new File(path);
boolean flag3 = file3.mkdirs();
System.out.println(flag3);
//創建文件--createNewFile()
File file = new File("/Users/braincao/git/2.txt");
if(!file.exists()){ //如果不存在則創建新文件,存在就不創建
file.createNewFile();
}
// if(file.exists()){
// file.delete();//如果存在則刪除文件,不存在就不創建
// }
//創建臨時文件,程序退出即刪除
File tmp = File.createTempFile("test", ".temp", new File("/Users/braincao/git"));
Thread.sleep(2000);//放大延時便於觀看效果
tmp.deleteOnExit();//文件退出即刪除
//輸出當前系統的根目錄--listRoots()
File[] roots = File.listRoots(); //當前系統的根目錄
}
@Test
public void test2(){
//遍歷文件夾中的文件--String[] list()
File file4 = new File("/Users/braincao/git");
if(file4.isDirectory()){ //如果是目錄路徑
String[] lists = file4.list(); //返回的是文件夾中所有東西的路徑字符串,不是File對象
for(String s: lists){
System.out.println(s);
}
System.out.println("=========");
File[] files = file4.listFiles();//返回的是文件夾中所有東西的File對象
for(File f: files){
System.out.println(f.getName());
}
System.out.println("=========");
//命令設計模式
//FilenameFilter()--設置過濾模板,顯示想要的文件或路徑
File[] ff = file4.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return new File(dir, name).isFile() && name.endsWith(".txt"); //返回後綴.txt的文件(非路徑)
}
});
for(File f: ff){
System.out.println(f.getName());
}
}
}
輸出子孫級目錄的絕對路徑名稱—遞歸
static void test3(String path) throws Exception{
/**
* @Description: 輸出子孫級目錄的絕對路徑名稱---遞歸
*/
File file = new File(path);
if(file.isFile()){
System.out.println(file.getAbsolutePath());
return;
}
File[] ff = file.listFiles();
for(File f: ff){
if(f.isFile()){
System.out.println(f.getAbsolutePath());
}
else{
test3(f.getAbsolutePath());
}
}
}
public static void main(String[] args) throws Exception{
test3("/Users/braincao/git/test");
}
2.IO:
- 節點流:節點流處於IO操作的第一線,所有操作必須通過它們進行
-
字節流
-
字符流
- 處理流:處理流可以對其他流進行處理(增強功能,提高效率)
字節流:二進制流,可以處理一切文件,包括純文本、doc、音頻、視頻等等
輸入流:InputStream--read(byte[] b)、read(byte[] b, int off, int len)、close()
FileInputStream()
輸出流:OutputStream--write(byte[] b)、write(byte[] b, int off, int len)、flush()、close()
FileOutputStream()
字符流:文本流,只能處理純文本
輸入流:Reader--read(char[] cbuf)、read(char[] cbuf, int off, int len)、close()
FileReader()
輸出流:Writer--write(char[] cbuf)、write(String[] str, int off, int len)、write(char[] cbuf, int off, int len)、flush()、close()
FileWriter()
2.1字節流
讀取文件input、寫入文件output的demo
@Test
public void input(){
/**
* @Description: 讀取文件
* 1.建立聯繫:File對象
2.選擇流:字節輸入流:InputStream FileInputStream
3.操作:數組大小byte[] b = new byte[1024]、read、write
4.釋放資源
*/
//1.建立聯繫
File file = new File("/Users/braincao/git/1.txt");
//2.選擇流,這裏有異常需要try catch
InputStream input = null; //提升作用域便於後面釋放資源
try {
input = new FileInputStream(file);
//3.操作:不斷讀取
byte[] b = new byte[10]; //每次最多讀取10字節的緩衝數組
int len = 0;//每次讀取的真實字節長度
//循環讀取
while(-1 != (len=input.read(b))){
//輸出,需要將字節數組轉成String
String str = new String(b, 0, len);
System.out.println(str);
}
} catch (IOException e) {
e.printStackTrace();
}finally{
if(input!=null){
try {
input.close(); //釋放資源
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void output(){
/**
* @Description: 寫出文件
* 1.建立聯繫:File對象
2.選擇流:字節輸出流:OutputStream FileOutputStream
3.操作:write、flush、close
4.釋放資源
*/
//1.建立聯繫
File file = new File("/Users/braincao/git/2.txt");
//2.選擇流
OutputStream output = null;//提升作用域便於後面釋放資源
try {
output = new FileOutputStream(file, true);//true是追加寫入,false是覆蓋寫入
String str = "hello world!\n";
//將String轉成byte數組
byte[] b = str.getBytes();
try {
output.write(b, 0, b.length); //3.操作:寫入文件
output.flush(); //強制刷新出去。如果沒有強制刷新,IO管道滿了或者需要等到釋放資源時,纔會flush推出寫入。因此要養成手動flush的習慣
} catch (IOException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}finally{
if(output!=null){
try {
output.close(); //釋放資源
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
#####拷貝文件、拷貝文件夾
拷貝文件:實現文件拷貝。結合了輸入流input和輸出流output,邊讀取邊寫入
拷貝文件夾
1.遞歸查找子孫級文件/文件夾
2.文件:IO流複製;文件夾:創建並遞歸下一級
@Test
public static void copy(String pathSrc, String pathDest) throws IOException {
/**
* @Description: 實現文件拷貝。結合了輸入流input和輸出流output,邊讀取邊寫入
* 1.建立聯繫:File對象
2.選擇流:字節輸入流:InputStream FileInputStream
字節輸出流:OutputStream FileOutputStream
3.操作:數組大小byte[]+read
write
flush+close
4.釋放資源
*/
//1.建立聯繫
File fileSrc = new File(pathSrc);
File fileDest = new File(pathDest);
//2.選擇流
InputStream input = null;
OutputStream output = null; //提升作用域便於後面釋放資源
try {
input = new FileInputStream(fileSrc);
output = new FileOutputStream(fileDest);
byte[] b = new byte[1024]; //讀取與寫入緩衝數組
int len = 0;
while(-1 != (len=input.read(b))){ //讀取
try {
output.write(b, 0, len); //寫入
} catch (IOException e) {
e.printStackTrace();
}
}
output.flush();//強制刷新出去
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally{
try {
if(input!=null){
input.close();
}
if(output!=null){
output.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Test
public static void copyFileDir(String pathSrc, String pathDest){
/**
* @Description: 文件夾拷貝,遞歸實現
* 1.遞歸查找子孫級文件/文件夾
* 2.文件:IO流複製;文件夾:創建並遞歸下一級
*/
//1.建立聯繫
File fileSrc = new File(pathSrc);
File fileDest = new File(pathDest + File.separator + fileSrc.getName());
if(fileSrc.isFile()){//如果是文件,IOcopy
System.out.println("====file");
try {
if(!fileDest.exists()){
copy(fileSrc.getAbsolutePath(), fileDest.getAbsolutePath());
}
} catch (IOException e) {
e.printStackTrace();
}
}
else if(fileSrc.isDirectory()){ //如果是文件夾路徑,創建路徑並遞歸遍歷
System.out.println("====fileDir");
if(!fileDest.exists()){
fileDest.mkdir(); //創建文件夾路徑
System.out.println("chuangjianchenggong ");
}
File[] ff = fileSrc.listFiles();
for(File f: ff){
copyFileDir(f.getAbsolutePath(), fileDest.getAbsolutePath());
}
}
}
public static void main(String[] args) throws Exception{
//文件拷貝: IO流
//copy("/Users/braincao/git/1.txt", "/Users/braincao/git/2.txt");
/*文件夾拷貝: 文件->IO流複製;文件夾->創建路徑並遞歸
*最終是把/Users/braincao/git/test文件夾拷貝到了/Users/braincao/git/test2/test中
*/
copyFileDir("/Users/braincao/git/test", "/Users/braincao/git/test2");
}
2.2 字符流
只能處理純文本,全部爲可見字符。
讀取:Reader FileReader
寫入:Writer FileWriter
@Test
public void charInputStream() throws IOException {
/**
* @Description: 字符流。從文本讀取
* 1.建立聯繫:File對象
2.選擇流:字符輸入流:Reader FileReader
3.操作:數組大小char[] b = new byte[1024]、read、close
4.釋放資源
*/
//1.建立聯繫
File src = new File("/Users/braincao/git/1.txt");
Reader r = null;
//2.選擇流
try {
r = new FileReader(src);
//3.操作
char[] cbuf = new char[10];
int len = 0;
while(-1 != (len=r.read(cbuf))){
String ss = new String(cbuf, 0, cbuf.length);
System.out.println(ss);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
finally {
if(r!=null){
r.close();
}
}
}
@Test
public void charOutputStream() throws IOException {
/**
* @Description: 字符流。寫入文本到文件
* 1.建立聯繫:File對象
2.選擇流:字符輸入流:Writer FileWriter
3.操作:write、flush、close
4.釋放資源
*/
//1.建立聯繫
File dest = new File("/Users/braincao/git/2.txt");
//2.選擇流
Writer w = null;
try {
w = new FileWriter(dest, true);//true追加;false覆蓋
//3.操作
String data = "asdadasdasdqweasd";
w.write(data);
w.append("\nsada");
w.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
finally {
if(w!=null){
w.close();
}
}
}
3.處理流:在節點流之上,處理流可以對其他流進行處理(增強功能,提高效率)
爲什麼要有緩衝流?
比如說,家裏蓋房子,有一堆磚頭要搬在工地100米外,單字節的讀取就好比你一個人每次搬一塊磚頭,從堆磚頭的地方搬到工地,這樣可定很費時間,然後好的方法就是多叫幾個小夥伴幫你一起搬磚頭,這樣因爲人多了,每次可以搬十塊磚頭,但效率還是很低,這就好比我們的字節/字符數組讀寫操作;然而聰明的人類會用小推車,每次先搬磚頭搬到小車上,再利用小推車運到工地上去,這樣你或者你的小夥伴們再從小推車上取磚頭是不是方便多了呀!這樣效率就會大大提高,緩衝流就好比我們的小推車;給磚頭暫時提供一個可存放的空間;
針對字節的處理流:字節緩衝流
- BufferedInputStream–直接把緩衝流加在字節流上就行,其他與字節流完全一樣
- BufferedOutputStream–建議今後都加上緩衝流,提高性能
針對字符流的處理流:字符緩衝流
- BufferedReader 新增readLine()
- BufferedWriter 新增newLine()
字節緩衝流demo:
@Test
public static void copy(String pathSrc, String pathDest) throws IOException {
/**
* @Description: 字節緩衝流--拷貝文件demo
* 緩衝流直接加在字節流上
*/
//1.建立聯繫
File fileSrc = new File(pathSrc);
File fileDest = new File(pathDest);
//2.選擇流
InputStream input = null;
OutputStream output = null; //提升作用域便於後面釋放資源
try {
input = new BufferedInputStream(new FileInputStream(fileSrc));//緩衝流直接加在字節流上
output = new BufferedOutputStream(new FileOutputStream(fileDest));
byte[] b = new byte[1024]; //讀取與寫入緩衝數組
int len = 0;
while(-1 != (len=input.read(b))){ //讀取
try {
output.write(b, 0, len); //寫入
} catch (IOException e) {
e.printStackTrace();
}
}
output.flush();//強制刷新出去
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally{
try {
if(input!=null){
input.close();
}
if(output!=null){
output.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
字符緩衝流demo:
在字符流上加緩衝流。有新增方法readline()、newLine()
@Test
public static void bufferedCharCopy(String pathSrc, String pathDest) throws IOException {
/**
* @Description: 字符流,拷貝文本文件。在字符流上加緩衝流。有新增方法readline()、newLine()
*/
//1.建立聯繫
File src = new File(pathSrc);
File dest = new File(pathDest);
//2.選擇流
Reader r = null;
Writer w = null;
try {
r = new BufferedReader(new FileReader(src)); //在字符流上加了緩衝流。有新增方法readLine()
w = new BufferedWriter(new FileWriter(dest)); //在字符流上加了緩衝流。有新增方法newLine()
// //3.1 讀取寫入操作
// char[] cbuf = new char[10];
// int len = 0;
// while(-1 != (len=r.read(cbuf))){
// w.write(cbuf, 0, cbuf.length);
// }
//3.2. 讀取寫入操作--用緩衝流的新增方法readLine()、newLine()
String line = null;
while(null != (line=((BufferedReader) r).readLine()) ){ //這裏用緩衝流的新增方法,不能使用多態
w.write(line);
((BufferedWriter) w).newLine();
}
w.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
finally {
if(r!=null){
r.close();
}
if(w!=null){
w.close();
}
}
}
public static void main(String[] args) throws IOException {
bufferedCharCopy("/Users/braincao/git/1.txt", "/Users/braincao/git/2.txt");
}
轉換流:將字符流轉爲字節流,將字節流轉爲字符流—>處理亂碼(編碼集、解碼集)
字符 --編碼集–> 二進制
字符 <–解碼集-- 二進制
出現亂碼原因:
- 1.編解碼字符集不統一
- 2.字節缺少,長度缺失(一箇中文字符需要兩個字節,少一個字節就亂碼)
編解碼例子:
@Test
public void test1() throws UnsupportedEncodingException {
/**
* @Description: 編解碼例子,idea平臺默認utf-8編解碼
*/
String str = "中國"; //utf-8解碼(將二進制解碼成了"中國")
byte[] b1 = str.getBytes(); //utf-8編碼(將字符串"中國"編碼成了utf-8)
byte[] b2 = str.getBytes("gbk"); //gbk編碼(將字符串"中國"編碼成了gbk)
System.out.println(new String(b1,"utf-8")); //解碼
System.out.println(new String(b1,"gbk")); //解碼
System.out.println(new String(b2,"utf-8")); //解碼
System.out.println(new String(b2,"gbk")); //解碼
/*out:
中國
涓浗
�й�
中國
*/
}
轉換流:
//輸入流(字節流-->字符流):InputStreamReader 解碼
//輸出流:OutputStreamWriter(字節流-->字符流) 編碼
@Test
public static void bufferedCharCharsetCopy(String pathSrc, String pathDest) throws IOException {
/**
* @Description: 當出現亂碼問題時,使用轉換流(字節流<--->字符流)
* 輸入流:InputStreamReader 解碼
輸出流:OutputStreamWriter 編碼
* 本例中:目的是:使用字符流進行文件拷貝
* 源文件(已知是gbk編碼的二進制文件),我們想用字符流(直接用會出現亂碼)
因此先用字節流,再用轉換流將字節流轉成字符流(解決編碼問題的字符流)
同時最後還是加上一層緩衝字符流
*/
//
File src = new File(pathSrc);
File dest = new File(pathDest);
//BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(src), "utf-8")); //指定解碼集,error亂碼,源文件是gbk因此解碼必須是gbk
//BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(src), "gbk")); //指定解碼集,ok
//BufferedWriter w = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(dest), "gbk")); //指定編碼集,ok
//BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(src), "gbk")); //指定解碼集,ok
//BufferedWriter w = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(dest), "utf-8")); //指定編碼集,ok
BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(src), "gbk")); //指定解碼集,ok
BufferedWriter w = new BufferedWriter(new FileWriter(dest)); //不指定編碼集,直接用字符流就行,也ok
String line = null;
while (null != (line = r.readLine())) {
System.out.println(line); //輸出解碼後的文本
w.write(line);
w.newLine();
}
w.flush();
w.close();
r.close();
}
public static void main(String[] args) throws IOException {
bufferedCharCharsetCopy("/Users/braincao/git/1.txt", "/Users/braincao/git/2.txt");
}
其他流:
-
字節數組流:將傳入的File對象換成了byte[]數組,其他一樣
輸入流:ByteArrayInputStream bArray = new ByteArrayInputStream(byte [] a);
輸出流:ByteArrayOutputStream bOut = new ByteArrayOutputStream();
byte[] dest = bOut.toByteArray() //這點不太一樣,要用這種方式傳給接受數組dest -
基礎數據類型處理流:基本類型+String,保留數據+類型
輸入流:DataInputStream readXxx()
輸出流:DataOutputStream writeXxx()
-
引用類型(對象)處理流:保留數據+類型,就是序列化、反序列化。通俗講就是把對象序列化保存到文件中,再從文件中反序列化拿出對象
反序列化(輸入流): ObjectInputStream readObject()
序列化(輸出流): ObjectOutputStream writeObject()
注意:
先序列化後反序列化,反序列化順序必須與序列化順序一致
不是所有對象都可以序列化,對象所在類要實現java.io.Serializable接口(空接口讓JVM識別)
每個對象有很多屬性,不是所有屬性都需要序列化,只序列化目標屬性即可。transient
序列化反序列化Demo:
import java.io.*;
/**
* @FileName: EmployeeDemo
* @Author: braincao
* @Date: 2018-10-07 11:35:10
* @Description: 序列化反序列化demo
*/
class Employee implements java.io.Serializable{
private String name;
private transient int id; //transient標識,不讓屬性序列化
public Employee(String name, int id) {
this.name = name;
this.id = id;
}
public Employee() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", id=" + id +
'}';
}
}
public class EmployeeDemo{
public static void main(String[] args) throws IOException, ClassNotFoundException {
Employee e = new Employee("張三", 2017111110);
//序列化
File outfile = new File("/Users/braincao/git/2.txt");
ObjectOutputStream os = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(outfile)));
os.writeObject(e);
os.close();
//反序列化
File infile = new File("/Users/braincao/git/2.txt");
ObjectInputStream is = new ObjectInputStream(new BufferedInputStream(new FileInputStream(infile)));
Object obj = is.readObject();
if(obj instanceof Employee){
Employee tmp = (Employee)obj;
System.out.println(tmp.getName());
System.out.println(tmp.getId()); //transient修飾的屬性不可見
}
is.close();
//out:張三 0
}
}
打印流:
System.out.println(“hello world”);中的out定義public final static PrintStream out = null;
,可見out就是PrintStream打印流
demo1:
import java.io.*;
public class PrintDemo {
public static void main(String[] args) throws IOException {
/**
* @Description: 打印流PrintStream(OutputStream out)demo
*/
//1.創建源
String ss = "鋤禾日當午,汗滴禾下土";
//2.選擇流
PrintStream ps = new PrintStream(new BufferedOutputStream(new FileOutputStream(new File("/Users/braincao/git/2.txt"))));
//3.操作
ps.write(ss.getBytes());
//4.釋放資源
ps.close();
}
}
demo2:
import java.io.*;
import java.util.Scanner;
public class PrintDemo {
public static void test1() throws IOException {
/**
* @Description: 打印流PrintStream(OutputStream out)demo
* 輸出到文件
*/
//1.創建源
String ss = "鋤禾日當午,汗滴禾下土";
//2.選擇流
PrintStream ps = new PrintStream(new BufferedOutputStream(new FileOutputStream(new File("/Users/braincao/git/2.txt"))));
//3.操作
ps.write(ss.getBytes());
//4.釋放資源
ps.close();
}
public static void test2() throws FileNotFoundException {
/**
* @Description:三個常量
* System.in --輸入流InputStream,默認是從鍵盤輸入
* System.out --輸出流OutputStream,默認是控制檯輸出
* System.err(與System.out一樣,就是輸出顏色不同)
*/
//輸出流
System.out.println("asd");
System.err.println("asd");
//輸入流1
InputStream is = System.in; //輸入流,鍵盤輸入
Scanner sc = new Scanner(is); //獲取鍵盤輸入的輸入流
System.out.println(sc.nextLine());
//輸入流2
BufferedInputStream fs = new BufferedInputStream(new FileInputStream(new File("/Users/braincao/git/2.txt")));
Scanner sc2 = new Scanner(fs); //獲取文件輸入的輸入流
System.out.println(sc2.nextLine());
}
public static void test3() throws FileNotFoundException {
/**
* @Description:將System.in、System.out重定向,不再使用默認的鍵盤輸入、控制檯輸出
* 重新分配“標準”輸入/出流:System類方法:setIn(InputStream in)、setOut(PrintStream out)、setErr(PrintStream err)
*/
PrintStream ps = new PrintStream(new BufferedOutputStream(new FileOutputStream(new File("/Users/braincao/git/2.txt"))), true);//autoFlush設爲true,如果不加一定要手動flush
System.setOut(ps); //重定向輸出流
System.out.println("哈哈1234"); //直接寫入到文件
ps.flush();
ps.close();
/**
* @Description:重定向後又想重新設爲控制檯
* FileDescriptor.in 鍵盤輸入
* FileDescriptor.out 控制檯輸出
*/
ps = new PrintStream(new BufferedOutputStream(new FileOutputStream(FileDescriptor.out)),true);
System.setOut(ps); //重定向輸出流
System.out.println("哈哈1234");
}
public static void main(String[] args) throws IOException {
//test1();
//test2();
test3();
}
}
裝飾設計模式
IO流用到的就是裝飾設計模式,包裝後增強功能
/**
* @FileName: Decrator
* @Author: braincao
* @Date: 2018/10/7 16:29
* @Description: 裝飾設計模式Demo---擴音器例子。IO流用到的就是裝飾設計模式,包裝後增強功能
*/
class Voice{
private int voice = 10; //初始音量爲10
public Voice() {
}
public void say(){
System.out.println(voice); //播放聲音,音量爲10
}
public int getVoice() {
return voice;
}
public void setVoice(int voice) {
this.voice = voice;
}
}
class Amplify{
private Voice voice;
public Amplify(Voice voice) {
this.voice = voice;
}
public void say(){
System.out.println(voice.getVoice()*100); //放大音量,現在爲1000
}
public Voice getVoice() {
return voice;
}
public void setVoice(Voice voice) {
this.voice = voice;
}
}
public class Decrator {
public static void main(String[] args){
Voice v = new Voice();
v.say(); //音量爲10
Amplify am = new Amplify(v);
am.say(); //音量爲1000
}
}
文件分割與合併Demo1
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Properties;
import java.io.*;
/**
* @Description: 文件分割與合併的demo
*/
public class TestDemo {
public static void main(String[] args) throws IOException {
File fileSplit = new File("/Users/braincao/git/test/xiezhu_pub.rar"); //要分割的文件,分割後存放的目錄也在同級目錄中
File fileMerge = new File("/Users/braincao/git/test"); //存放分割文件的目錄,合併後的文件也存在此目錄中
// split(fileSplit);
merge(fileMerge);
}
//文件分割
public static void split(File file) throws IOException {
FileInputStream fis = new FileInputStream(file);
FileOutputStream fos = null;
byte[] buf = new byte[1024*1024]; //每個分割文件的大小
int len = 0;
int count = 1;
while(-1 != (len=fis.read(buf))){
fos = new FileOutputStream(new File(file.getParent(), count+".part"));
count++;
fos.write(buf, 0, len);
fos.flush();
}
fis.close();
//輸出寫入配置文件
Properties prop = new Properties();
fos = new FileOutputStream(new File(file.getAbsoluteFile() + ".properties" ));
prop.setProperty("fileName", file.getName());
prop.setProperty("partCount", (count-1)+"");
prop.store(fos,"save file info");
fos.close();
}
//文件合併
public static void merge(File file) throws IOException{
//1.拿到properties中的相關信息
File[] propFiles = file.listFiles(new SuffixFilter(".properties"));
if(propFiles.length!=1){
throw new RuntimeException(file+"該目錄下沒有properties擴展名的文件或者不唯一");
}
Properties pp = new Properties();
FileInputStream propInput = new FileInputStream(propFiles[0]);
pp.load(propInput);
String fileName = pp.getProperty("fileName");
int partNum = Integer.parseInt(pp.getProperty("partCount"));
//2.遍歷目錄中.part文件,用SequenceInputStream輸入流組合
ArrayList<FileInputStream> fis = new ArrayList<>();
File[] files = file.listFiles(new SuffixFilter(".part"));
for(int i=0; i<files.length; ++i){
fis.add(new FileInputStream(files[i]));
}
Enumeration<FileInputStream> efis = Collections.enumeration(fis);
SequenceInputStream sis = new SequenceInputStream(efis);
//3.輸入流:SequenceInputStream;輸出流:FileOutputStream--->拷貝寫入
FileOutputStream fos = new FileOutputStream(new File(file.getAbsolutePath(), "Merge_" + fileName));
byte[] b = new byte[1024*1024];
int len = 0;
while(-1 != (len=sis.read(b))){
fos.write(b, 0, len);
fos.flush();
}
fos.close();
sis.close();
}
}
class SuffixFilter implements FilenameFilter{
private String suffix;
public SuffixFilter(String suffix){
super();
this.suffix = suffix;
}
@Override
public boolean accept(File dir, String name) {
return name.endsWith(suffix);
}
}
文件分割與合併Demo2(這個包含很多知識點,建議詳看)
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
/**
* @FileName: RandomAccessFileDemo
* @Author: braincao
* @Date: 2018/10/7 16:52
* @Description: 文件分割與合併Demo
* 文件分割思路:
* 1.確定每一塊的大小 blockSize
* 2.已知文件總大小length和blockSize,計算確定分割的塊數 n=Math.ceil(length/blockSize) //Math.ceil(double a)返回大於等於a的最小整數(返回double類型)
* 3.確定最後一塊的大小 length - (n-1)*blockSize
*/
public class SplitFileDemo {
private String filePath; //源文件路徑
private String fileName; //源文件名
private long length; //源文件名
private String destPath; //分割後文件存放目錄
private long blockSize; //每塊的大小
private List<String> blockPath; //每塊的名稱
private int n; //分割的塊數
public SplitFileDemo(String filePath, String destPath){
this(filePath, destPath, 10);
}
public SplitFileDemo(String filePath, String destPath, long blockSize){
blockPath = new ArrayList<>();
this.filePath = filePath;
this.destPath = destPath;
this.blockSize = blockSize;
init(); //初始化各項參數
}
private void init(){
/**
* @Description: 初始化操作:修正每塊大小、計算塊數、確定文件名
*/
File src = null;
//健壯性
if(null==filePath || !(src=new File(filePath)).exists() || !(src.isFile()) ){
return;
}
//文件名
this.fileName = src.getName();
//修正每塊大小、計算塊數
this.length = src.length(); //文件實際大小
if(this.blockSize > length){//修正每塊大小
this.blockSize = length;
}
//確定塊數
n = (int)Math.ceil(length*1.0/this.blockSize); //Math.ceil(double a)返回大於等於a的最小整數,返回double類型
initPathName(destPath);
}
private void initPathName(String destPath){//確定文件名
for(int i=0; i<n; ++i){
blockPath.add(destPath + "/" + fileName + ".part" + i);
}
}
//文件分割
public void split(){
/**
* @Description: 上面都是爲文件分割做準備,現在開始分割
* @Param: [destPath] 分割文件存放的目錄
* 文件分割:
* 第幾塊、起始位置、實際大小
*/
long beginPos = 0; //起始點
long actualBlockSize = blockSize; //實際大小
for(int i=0; i<n; ++i){
if(i==n-1){
actualBlockSize = this.length-beginPos;
}
splitDetail(i, beginPos, actualBlockSize);
beginPos += actualBlockSize;
}
}
private void splitDetail(int blockNum, long beginPos, long actualBlockSize){
/**
* @Description:文件分割的具體操作,其實就是文件拷貝過程
* 輸入流:RandomAccessFile
* 輸出流: FileOutputStream
* @Param: [blockNum, beginPos, actualBlockSize] 第幾塊、起始點、實際每塊大小(主要針對最後一塊)
*/
//1.創建源
File src = new File(this.filePath);
File dest = new File(this.blockPath.get(blockNum));
//2.選擇流
RandomAccessFile rnd = null;//參數"r"只讀
BufferedOutputStream fo = null;
try {
rnd = new RandomAccessFile(src, "r");
fo = new BufferedOutputStream(new FileOutputStream(dest));
//3.操作
rnd.seek(beginPos); //從beginPos位置開始讀取文件
byte[] b = new byte[1024]; //定義緩衝區
int len = 0;//實際讀取長度
//目標:從文件beginPos位置讀取actualBlockSize大小的東西,每次實際讀取len大小
while(-1 != (len=rnd.read(b))){
if(len<actualBlockSize){
fo.write(b, 0, len); //寫入文件
fo.flush();
actualBlockSize -= len;
}
else{//最後一塊了
fo.write(b, 0, (int)actualBlockSize); //寫入文件
fo.flush();
break;
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
if(rnd!=null){
rnd.close();
}
if(fo!=null){
fo.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
//文件合併--法1
public void mergeFile(String destPath) {
/**
* @Description:文件合併的具體操作,其實就是文件拷貝過程
* 輸入流:FileInputStream
* 輸出流: FileOutputStream
* @Param: [destPath] 合併後文件的存放目錄
*/
File dest = new File(destPath);
BufferedOutputStream fo = null;
try {
fo = new BufferedOutputStream(new FileOutputStream(dest,true));
for (int i = 0; i < blockPath.size(); ++i) {
//1.創建源
File src = new File(this.blockPath.get(i));
//2.選擇流
BufferedInputStream fs = null;//參數"r"只讀
fs = new BufferedInputStream(new FileInputStream(src));
//3.操作
byte[] b = new byte[1024]; //定義緩衝區
int len = 0;//實際讀取長度
while (-1 != (len = fs.read(b))) {
fo.write(b, 0, len); //寫入文件
fo.flush();
}
fs.close();
}
}catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try{
if (fo != null) {
fo.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
//文件合併--法2--SequenceInputStream:將很多流組合成一個流的InputStream
public void merge2(String destPath){
/**
* @Description: SequenceInputStream(Enumeration<? extends InputStream> e)
* Enumeration:vector
* @Param:
* @return: void
*/
//1.創建源
File dest = new File(destPath);
//2.選擇流
SequenceInputStream sis = null; //輸入流
BufferedOutputStream fo = null; //輸出流
//創建一個容器用於後面組合流
Vector<InputStream> vi = new Vector<>();
try {
for (int i = 0; i < blockPath.size(); ++i){
vi.add(new BufferedInputStream(new FileInputStream(new File(this.blockPath.get(i)))));
}
sis = new SequenceInputStream(vi.elements()); //SequenceInputStream組合流;vi.elements()返回此向量的枚舉
fo = new BufferedOutputStream(new FileOutputStream(dest,true));
//3.操作
byte[] b = new byte[1024]; //定義緩衝區
int len = 0;//實際讀取長度
while (-1 != (len = sis.read(b))) {
fo.write(b, 0, len); //寫入文件
fo.flush();
}
}catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try{
if (fo != null) {
fo.close();
}
if (sis != null) {
sis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args){
String fileSrc = "/Users/braincao/git/1.txt"; //要分割的文件
String destPath = "/Users/braincao/git"; //分割後文件存放目錄
String destMergePath = "/Users/braincao/git/test.txt"; //合併後文件的路徑
SplitFileDemo file = new SplitFileDemo(fileSrc, destPath, 20);
file.split(); //文件分割
// file.mergeFile(destMergePath); //文件合併--法1
file.merge2(destMergePath); //文件合併--法2
}
}
File類的一個例子
獲取git目錄下後綴名爲.txt的文件
public static void test1(){
File file = new File("/Users/braincao/git");
FilenameFilter filter = new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".txt"); //文件名的後綴要以.txt
}
};
String[] ff = file.list(filter);
for(String f: ff){
System.out.println(f);
}
}
日期Date、Calendar相關Demo
打印指定日期的月曆:
import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
import java.util.Scanner;
/**
* @Description: 鍵盤輸入一個日期,打印該日期所在月份的月曆
*/
public class TestDemo{
public static void main(String[] args) throws ParseException {
//1.獲取輸入字符串的日期
System.out.println("請輸入想要查看的日期:(2018-11-09)");
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
Date d = java.sql.Date.valueOf(s);
Calendar cal = Calendar.getInstance();
cal.setTime(d);
int thisDay = cal.get(Calendar.DAY_OF_MONTH); //指定的日期
int days_of_month = cal.getActualMaximum(Calendar.DAY_OF_MONTH); //這個月有多少天。getActualMaximum-->返回指定Calendar日曆字段可能擁有的最大值。
cal.set(Calendar.DAY_OF_MONTH, 1);
int week_of_firstDay_of_month = cal.get(Calendar.DAY_OF_WEEK); //這個月1號是周幾
//2.打印指定日期的月份
System.out.println("日\t一\t二\t三\t四\t五\t六");//1週日 2週一 3週二 4週三 5週四 6週六 7週日
//2.1 打印1號之前的空格
String suffixHead = "";
for(int i=1; i<=week_of_firstDay_of_month-1; ++i){
suffixHead = suffixHead+"\t";
}
System.out.print(suffixHead);
int cnt = week_of_firstDay_of_month; //打印月曆時換行的計數器
//2.2 打印本月月份,並將指定的當天日期後加"*"
for(int cntDay=1; cntDay<=days_of_month; ++cntDay){
if(cntDay==thisDay){
System.out.print(cntDay + "*\t");
}
else{
System.out.print(cntDay + "\t");
}
//判斷是否換行
if(cnt%7 == 0){
System.out.println();
cnt = 1;
}
else{
cnt++;
}
}
}
}
out:
請輸入想要查看的日期:(2018-11-09)
2018-10-09
日 一 二 三 四 五 六
1 2 3 4 5 6
7 8 9* 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
枚舉Demo
什麼情況用枚舉:值比較少且固定時
import java.text.ParseException;
/**
* @Description: 枚舉使用Demo
*/
enum Gendar{ //枚舉
男, 女
}
class Person{
private String name;
private int age;
private Gendar sex; //使用枚舉
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", sex=" + sex +
'}';
}
public Person(String name, int age, Gendar sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
public Person() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Gendar getSex() {
return sex;
}
public void setSex(Gendar sex) {
this.sex = sex;
}
}
public class TestDemo{
public static void main(String[] args) throws ParseException {
Person p = new Person();
p.setName("張三");
p.setAge(25);
p.setSex(Gendar.男); //用枚舉進行設置。好處:如果是String類型的sex,會遇到亂七八糟的String,這樣給判斷String帶來很多麻煩,用枚舉更好
System.out.println(p.toString());
//枚舉與switch結合使用
Gendar sex = Gendar.女;
switch (sex){
case 男:
System.out.println("這是男孩");
break;
case 女:
System.out.println("這是女孩");
break;
}
}
}
Math.random()與Random r = new Random(long seed)
public static void main(String[] args){
System.out.println(Math.random()*10);
System.out.println("-------------");
Random r = new Random(10); //new Random(long seed)seed是生成隨機數的種子,seed不變生成的隨機數也不變,seed變了隨機數也就變了
for(int i=0; i<5; ++i){//重複運行發現生成的隨機數都相同,僞隨機數
System.out.println(r.nextInt());
}
System.out.println("-------------");
Random r1 = new Random(System.currentTimeMillis()); //new Random(long seed)seed是生成隨機數的種子,seed不變生成的隨機數也不變,seed變了隨機數也就變了
for(int i=0; i<5; ++i){//重複運行發現生成的隨機數都不同,因爲種子變了
System.out.println(r1.nextInt());
}
}
out:
1.7647342360229157
-------------
-1157793070
1913984760
1107254586
1773446580
254270492
-------------
958951514
-1748165986
967614401
9816424
-782039092
管道流
PipedInputStream和PipedOutputStream:輸入輸出可以直接進行連接,通過結合線程使用。
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
/**
* @Description: 管道流結合多線程使用
*/
public class TestDemo{
public static void main(String[] args) throws IOException {
PipedInputStream input = new PipedInputStream();
PipedOutputStream output = new PipedOutputStream();
input.connect(output);
new Thread(new Input(input)).start(); //Input是一個線程
new Thread(new Output(output)).start(); //Output是一個線程
}
}
class Input implements Runnable{
private PipedInputStream in;
public Input(PipedInputStream in){
this.in = in;
}
public void run(){
try{
byte[] buf = new byte[1024];
int len = in.read(buf);
String s = new String(buf, 0, len);
System.out.println("s=" + s);
in.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
class Output implements Runnable{
private PipedOutputStream out;
public Output(PipedOutputStream out){
this.out = out;
}
public void run(){
try{
out.write( "hi,管道來了!".getBytes());
out.flush();
out.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
//out: s=hi,管道來了!