IO流

28 阅读8分钟

1. File类

File类提供了用于操作文件 或者获取文件信息的方法

package com.qfedu.test1;

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

/**
 * 	文件类 提供了用于操作文件 或者获取文件信息的方法
 * @author WHD
 *
 */
public class TestFile {
	public static void main(String[] args) throws IOException {
		File file2 = new File("C:\\Users\\WHD\\Desktop\\A.txt");
		
		System.out.println("使用绝对路径在桌面创建文件:" +  file2.createNewFile());	
		
		File file1 = new File("A.txt");
		
		System.out.println("使用相对路径在本项目中创建文件:" + file1.createNewFile());
		
		System.out.println("文件名是:" + file1.getName());
		
		System.out.println("文件大小是,字节为单位:" + file1.length());
		
		System.out.println("文件的相对路径 是:" + file1.getPath());

		System.out.println("文件的绝对路径是:" + file1.getAbsolutePath());
		
		System.out.println("文件是否存在:" + file1.exists());
		
		System.out.println("file1是否是文件夹:" + file1.isDirectory());
		
		System.out.println("file1是否是文件:" + file1.isFile());
		
		System.out.println("file1是否是隐藏文件:" + file1.isHidden());
		
		System.out.println("删除文件:" + file1.delete());
		
		File file3 = new File("A");
		
		System.out.println(file3.mkdir()); // makeDirectory
		
		file3.delete();
		
		File file4 = new File("B/C/D");
		
		file4.mkdirs();
		
		file4.delete();
	}
}

2. 字节流

2.1 读

  • InputStream 父类 抽象类
    • FileInputStream  子类

InputStream抽象类

FileInputStream 子类

read() 读取一个字节 返回值为读取的内容的ascii码

read(byte [] data) 返回值为读取内容的字节数  读取的内容在byte数组中

close() 关闭流

available() 获取输入流可读取的字节数

package com.qfedu.test2;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

/**
 * 	InputStream抽象类
 * 	FileInputStream 子类
 * 	
 * 	read() 读取一个字节 返回值为读取的内容的ascii码
 * 	read(byte [] data) 返回值为读取内容的字节数  读取的内容在byte数组中
 * 
 * 	close() 关闭流 
 * 	available() 获取输入流可读取的字节数 
 * @author WHD
 *
 */
public class TestFileInputStream1 {
	public static void main(String[] args) {
		FileInputStream fis = null;
		try {
			fis = new FileInputStream("A.txt");
						
			int readData = -1;
			
			while((readData = fis.read()) != -1) {
				System.out.println((char)readData);
			}
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			try {
				if(fis != null) { // 这里做非null 判断 可以避免空指针异常
					fis.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}
package com.qfedu.test3;

import java.io.FileInputStream;
import java.io.IOException;

/**
 * 	read(byte [] data) 返回值为读取的字节数  读取的内容在byte数组中
 * @author WHD
 *
 */
public class TestFileInputStream2 {
	public static void main(String[] args) throws IOException {
		FileInputStream fis = new FileInputStream("A.txt");
		
		System.out.println(fis.available());
		
		int readCount = -1;
		
		// 我们在使用byte数组读取的时候 为了避免截断中文造成乱码 可以有以下两种解决方法
		// 1.定义一个较长的byte数组
		// 2.直接以当前文件的可读字节数作为byte数组的长度(推荐)
		byte [] data = new byte[fis.available()];
		
		while((readCount = fis.read(data)) != -1) {
			// 第一个参数为解析对象 byte数组
			// 第二个参数从数组中的哪个下标开始解析
			// 第三个参数 表示解析多长
			System.out.println(new String(data, 0, readCount));
		}
		
		if(fis != null) {
			fis.close();  // 移动整行 alt + 方向键
		}
	}
}

2.2 写

  • OutputStream
    • FileOutputStream

OutputStream 字节写入流父类

FileOutputStream 字节写入类子类

write(byte [] data)每次写入一个字节数组

close() 关闭资源

flush() 将写入内容刷新到文件

字节写入流

package com.qfedu.test4;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 	OutputStream
 * 	FileOutputStream
 * 
 * 	write(byte [] data)
 * 
 * 	close()
 * 	flush()
 * 	
 * 	字节写入流
 * @author WHD
 *
 */
public class TestFileOutputStream1 {
	public static void main(String[] args) {
		try {
			FileOutputStream fos = new FileOutputStream("B.txt",true); // 第二个true 表示追加内容
			
			String str = "hello 中国";
			
			byte[] bytes = str.getBytes(); // 将字符串转换为byte数组
			
			fos.write("abcd你好".getBytes()); 
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			// 关闭资源
		}
	}
}
package com.qfedu.test4;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilterOutputStream;
import java.io.IOException;

/**
 * 	OutputStream
 * 	FileOutputStream
 * 
 * 	write(int data)
 * 	close()
 * 	flush()
 * 	
 * 	字节写入流
 * @author WHD
 *
 */
public class TestFileOutputStream2 {
	public static void main(String[] args) {
		try {
			FileOutputStream fos = new FileOutputStream("B.txt",true); // 第二个true 表示追加内容
			
			fos.write(97); 
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			// 关闭资源
		}
	}
}

3. 字符流

3.1 Reader

3.1.1 InputStreamReader

Reader

InputStreamReader

read() 每次读取一个字符

read(char [] data) 每次读取一个字符数组

close() 关闭资源

package com.qfedu.test5;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * 	Reader
 * 	InputStreamReader
 * 
 * 	read() 每次读取一个字符
 * 	read(char [] data) 每次读取一个字符数组
 * 
 * 	close() 关闭资源
 * @author WHD
 *
 */
public class TestInputStreamReader1 {
	public static void main(String[] args) throws IOException {
		FileInputStream fis = new FileInputStream("A.txt");
		InputStreamReader isr = new InputStreamReader(fis);
		int readData = -1;
		while((readData = isr.read()) != -1) {
			System.out.println((char)readData);
		}
		// 关闭资源 先用后关
		
		if(isr != null) {
			isr.close();
		}
		
		if(fis != null) {
			fis.close();
		}	
	}
}

read(char [] data) 每次读取一个字符数组

package com.qfedu.test5;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * 	read(char [] data) 每次读取一个字符数组
 * @author WHD
 *
 */
public class TestInputStreamReader2 {
	public static void main(String[] args) {
		try {
			InputStreamReader isr = new InputStreamReader(new FileInputStream("A.txt"));
			
			char [] data = new char[10];
			
			int readCount = -1;
			
			while((readCount = isr.read(data)) != -1) {
				System.out.println(new String(data, 0, readCount));
				
//				System.out.println(readCount);
				
//				System.out.println(data);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			// 关闭资源
		}
	}
}

读取桌面A.txt文件

乱码产生的原因:因为多个文件编码方式不一致导致

解决方案:将多个数据源编码方式统一

InputStreamReader 构造方法指定编码格式

将 源文件修改为和java程序一致的编码格式

ANSI 在中文win10 表示GBK

UTF-8 万国码 Unicode编码

package com.qfedu.test5;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * 	读取桌面A.txt文件
 * 
 * 	乱码产生的原因:因为多个文件编码方式不一致导致
 * 	解决方案:将多个数据源编码方式统一
 * 
 * 	InputStreamReader 构造方法指定编码格式
 * 	将 源文件修改为和java程序一致的编码格式
 * 
 * 	ANSI 在中文win10 表示GBK
 * 	UTF-8 万国码 Unicode编码
 * 	
 * @author WHD
 *
 */
public class TestInputStreamReader3 {
	public static void main(String[] args) throws IOException {
		InputStreamReader isr = new InputStreamReader(new FileInputStream("C:\\Users\\WHD\\Desktop\\A.txt"));
	
		int readData = -1;
		
		while((readData = isr.read()) != -1) {
			System.out.println((char)readData);
		}
		// 关闭资源
	}
}

3.1.2 FileReader

FileReader

该类只能按照本地平台的字符编码来读取数据,用户不能指定其他的字符编码类型

package com.qfedu.test6;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

/**
 * 	FileReader
 * 	该类只能按照本地平台的字符编码来读取数据,用户不能指定其他的字符编码类型
 * @author WHD
 *
 */
public class TestFileReader {
	public static void main(String[] args) throws IOException {
		// 获取本地平台JVM的文件编码格式
		System.out.println(System.getProperty("file.encoding"));
		System.out.println(System.getProperty("os.name"));
		System.out.println(System.getProperty("java.version"));
		
		System.getProperties().list(System.out); // 查看本机Java相关环境
			
		FileReader fr = new FileReader("A.txt");
		
		int readCount = -1;
		
		char [] data = new char[10];
		
		while((readCount = fr.read(data))!= -1) {
			System.out.println(new String(data,0,readCount));
		}
		// 关闭资源
	}
}

3.1.3 BufferedReader

BufferedReader  可以每次读取一行 提高读取效率

readLine()

package com.qfedu.test6;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * 	BufferedReader  可以每次读取一行 提高读取效率
 * 	readLine()
 * @author WHD
 *
 */
public class TestBufferedReader {
	public static void main(String[] args) throws IOException {
		FileInputStream fis = new FileInputStream("A.txt");
		InputStreamReader isr = new InputStreamReader(fis);
		BufferedReader br = new BufferedReader(isr);
		
		String line = null;
		while((line = br.readLine()) != null) {
			System.out.println(line);
		}
		
		// 关闭资源 先用后关		
	}
}

3.2 Writer

3.2.1 OutputStreamWriter

Writer 父类 抽象类

OutputStreamWriter

write(char data)

write(char [] data)

write(String str)

package com.qfedu.test7;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;

/**
 * 	Writer 父类 抽象类
 * 	OutputStreamWriter
 * 
 * 	write(char data)
 * 	write(char [] data)
 * 	write(String str)
 * @author WHD
 *
 */
public class TestOutputStreamWriter1 {
	public static void main(String[] args) throws IOException {
		OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("C.txt",true));
		
		osw.write("hello world \n 世界你好3333666666666hello   ");
		osw.close();	
	}
}

3.2.2 FileWriter

Writer

OutputStreamWriter

FileWriter

write()

package com.qfedu.test7;

import java.io.FileWriter;
import java.io.IOException;

/**
 * 	Writer
 * 	OutputStreamWriter
 * 	FileWriter
 * 
 * 	write()
 * @author WHD
 *
 */
public class TestFileWriter {
	public static void main(String[] args) throws IOException {
		FileWriter fw = new FileWriter("D.txt");
		
		fw.write("abcd中国666");
		
		fw.close();
	}
}

3.2.3 BufferedWriter

Writer

BufferedWriter

package com.qfedu.test7;

import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;

/**
 * 	Writer
 * 	BufferedWriter
 * @author WHD
 *
 */
public class TestBufferedWriter {
	public static void main(String[] args) throws IOException {
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("E.txt")));
		
		bw.write("a\nb\tc");
		
		bw.newLine();
		
		bw.write("世界你好");
		
		bw.flush(); // 将缓冲区中的内容刷新到文件
		 
		bw.close(); // 关闭之前会自动刷新缓冲区				
	}
}

4. 数据流

DataInputStream 用于读取二进制文件

DataOutputStream 写入二进制文件

package com.qfedu.test8;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 	DataInputStream 用于读取二进制文件
 * 	DataOutputStream 写入二进制文件
 * @author WHD
 *
 */
public class TestDataStream {
	public static void main(String[] args) throws IOException {
		FileInputStream fis = new FileInputStream("C:\\Users\\WHD\\Desktop\\37-200219113632-50.jpg");
		DataInputStream dis = new DataInputStream(fis);
		
		byte [] data = new byte[fis.available()];
		dis.read(data);
		
//		System.out.println(new String(data,0,data.length));
		
		DataOutputStream dos = new DataOutputStream(new FileOutputStream("girl.jpg"));
		
		dos.write(data);
		
		// 关闭资源	
	}
}

5. 序列化和反序列化

序列化:将对象保存为二进制文件,这个过程称之为序列化

反序列化:将存有对象的二进制文件,读取为对象,称之为反序列化

ObjectInputStream 读取对象

ObjectOutputStream 写入对象

readObject()  读取对象  返回值为对象

writeObject() 写入对象

被序列化的对象必须实现**Serializable**接口

使用transient修饰表示此属性不能被序列化

序列化 将对象转换为二进制流,保存到文件的过程 ObjectOutputStream/ writeObject

反序列化 从文件中读取二进制流,转换为对象 ObjectInputStream/ readObject

注意:对象的类要实现Serializable接口 针对不需要序列化的属性,使用transient 修饰

package com.qfedu.test8;

import java.io.Serializable;

public class Student implements Serializable{
	private transient String name; // 使用transient修饰表示此属性不能被序列化
	private int age;
	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 Student() {
	}
	public Student(String name, int age) {
		this.name = name;
		this.age = age;
	}
	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + "]";
	}
}
package com.qfedu.test8;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/**
 * 	ObjectInputStream 读取对象
 * 	ObjectOutputStream 写入对象
 * 
 * 	readObject()  读取对象  返回值为对象
 * 	writeObject() 写入对象 
 * @author WHD
 *
 */
public class TestObjectStream {
	public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
		Student stu1 = new Student("赵四", 17);
		Student stu2 = new Student("大拿", 18);
		
		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("stu.txt"));
		
		oos.writeObject(stu1);
		oos.writeObject(stu2);
		
		FileInputStream fis = new FileInputStream("stu.txt");
		
		ObjectInputStream ois =  new ObjectInputStream(fis);
		
		
		while(fis.available() > 0) {
			Object obj1 = ois.readObject();
			
			if(obj1 instanceof Student) {
				Student stu = (Student) obj1;
				System.out.println(stu);
			}
		}		
	}
}

这个serialVersionUID是用来辅助对象的序列化与反序列化的,原则上序列化后的数据当中的serialVersionUID与当前类当中的serialVersionUID一致,那么该对象才能被反序列化成功。这个serialVersionUID的详细的工作机制是:在序列化的时候系统将serialVersionUID写入到序列化的文件中去,当反序列化的时候系统会先去检测文件中的serialVersionUID是否跟当前的文件的serialVersionUID是否一致,如果一直则反序列化成功,否则就说明当前类跟序列化后的类发生了变化,比如是成员变量的数量或者是类型发生了变化,那么在反序列化时就会发生crash,并且回报出错误:

什么是Serializable接口

一个对象序列化的接口,一个类只有实现了Serializable接口,它的对象才能被序列化。

为什么要序列化对象

把对象转换为字节序列的过程称为对象的序列化把字节序列恢复为对象的过程称为对象的反序列化

什么是序列化?

序列化是将对象状态转换为可保持或传输的格式的过程。与序列化相对的是反序列化,它将流转换为对象。这两个过程结合起来,可以轻松地存储和传输数据。

什么情况下需要序列化?

当我们需要把对象的状态信息通过网络进行传输,或者需要将对象的状态信息持久化,以便将来使用时都需要把对象进行序列化