I/O流

问:IO流是什么,用IO流可以做什么?

   IO流指的是InputStream和OutputStream(就是输入/输出流),通过Input输入流,我们可以将外部的(磁盘、光盘上的)文件读入到程序中;通过Output输出流,我们可以将程序中的数据输出到外部设备上。


问:IO流都包括哪些内容?

IO流根据不同的标准可以有不同的分类:


IO流按处理的数据单位划分:以byte为单位的是字节流(InputStream/OutputStream),以char为单位的是字符流(Reader/Writer);按数据流的流向划分:从外部设备读取数据到程序的是输入流(InputStream/Reader),从程序向外部设备输出数据的是输出流(OutputStream/Writer);按流的角色划分:直接对文件对象进行操作的是节点流,包裹在文本流之上对文件对象进行操作的是处理流。下图为各个流分类之间的关系





下面表格将介绍一些比较关键常用的IO流:


缓冲流、转换流、对象流等都属于处理流


问:在知道IO流的分类和基本的IO流之后,我们又如何来通过类对象来实现程序与文件之间的交互呢?


一、File类:外部文件在程序中的代言人

IO流可以帮助我们对外部文件进行读取、修改和输出。但是,在那之前我们首先要知道java.io包下的另一个类:File类(java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据),因为我们在创建输入流对象的构造参数就是File类的对象。

//file为File类对象
FileInputStream fis = new FileInputStream(file);

关于File类,我们可以简单理解为:File类的对象在程序中就代表着我们要操作的外部文件。File类本身给提供了一些方法,让我们能够直接对外部文件进行部分操作,例如:创建新文件,删除已存在的文件,对文件进行重命名等。但是,File类不能够对文件的内容进行操作,例如:读取txt文本文件的内容并输出到控制台,这需要借用IO流才能实现。那么,我们接下来看看File类都提供了哪些方法:



接下来,我们来看看如何创建一个File类对象以及如何通过File类对象对文件进行相关操作。

import java.io.File;
import java.io.IOException;
import org.junit.Test;

public class TestFileBlog {
	
	@Test
	public void fileObject(){
		/*
		 * 1.创建File类对象
		 * 通过File类的构造函数public File(String pathname)可以创建File类的对象,
		 * 其中构造参数:pathname为目标文件的路径可以是相对路径也可以是绝对路径。
		 * 绝对路径:从盘符开始的路径,例如:E:\java\test.txt
		 * 相对路径:相对于当前文件的路径,例如:\java\1.jpg 表示当前工程目录下java文件夹下的1.jpg图片
		 *        相对路径使用的特殊符号:
		 *        --|"\" :代表根目录
		 *        --|".\" :代表目前所在的目录
		 *        --|"..\" :代表上一层目录
		 */
		File file = new File("E:\\IO\\test.txt");
		/*
		 * 2.访问文件信息
		 * --|getName() 返回文件名称(有后缀名)
		 * --|renameTo(File newname) 将文件重命名
		 */
		String fileName = file.getName();
//		file.renameTo(new File("E:\\IO\\test1.txt"));
		System.out.println("文件名称:" + fileName);
		/*
		 * 3.文件检测
		 * --|exists()
		 * --|canRead()
		 * --|canWrite()
		 */
		boolean exist = file.exists();
		boolean read = file.canRead();
		boolean write = file.canWrite();
		System.out.println("文件是否存在:" + exist);
		System.out.println("文件是否可读:" + read);
		System.out.println("文件是否可写:" + write);
		/*
		 * 4.文件常规信息:length()
		 */
		long length = file.length();
		System.out.println("文件长度为:" + length);
		/*
		 * 5.文件操作:
		 * --|createNewFile()
		 * --|delete()
		 */
		File file1 = new File("E:\\IO\\test2.txt");
		try {
			boolean create = file1.createNewFile();
			System.out.println("创建文件是否成功:" + create);
		} catch (IOException e) {
			e.printStackTrace();
		}
		boolean delete = file1.delete();
		System.out.println("删除文件是否成功:" + delete);
	}

}

上面的代码简单的介绍了,File类对象的创建以及一些常用方法的使用。在这里, 我们应该记住File类对象是如何创建的,因为创建IO流对象的构造参数便是File对象。


二、IO流的真正使用(从流的角色出发)

1、节点流( 字节流:FileInputStream  FileOutputStream       字符流:FileReader  FileWriter)

1.1、FileInputStream和FileOutputStream

	@Test
	public void test_In_OutputStream(){
		/*
		 * (文件复制)
		 * 读取E盘IO文件夹下test.txt文件,并将文件的内容输出到同文件夹下test1.txt文件中
		 */
		
		//1.创建File类对象
		File file = new File("E:\\IO\\test.txt");
		File file1 = new File("E:\\IO\\test1.txt");
		//2.创建输入输出流对象
		FileInputStream fis = null;
		FileOutputStream fos = null;
		try{
			fis = new FileInputStream(file);
			fos = new FileOutputStream(file1);
			//3.定义字节数组b接收输入流读取的内容,len为输入流对象读取内容的长度
			byte[] b = new byte[20];
			int len;
			//4.通过循环:fis遍历读取目标文件的内容,fos将内容复制到另一个文件中
			while((len = fis.read(b)) != -1){
				fos.write(b, 0, len);
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			//5.关闭输入输出流
			if(fos != null){
				try {
					fos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(fis != null){
				try {
					fis.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		
	}


注:

FileInputStream常用方法:

--|public FileInputStream(File file)  throws FileNotFoundException

参数:目标文件对象

异常:如果该文件不存在,或者它是一个目录,而不是一个常规文件,抑或因为其他某些原因而无法打开进行读取

返回值:无

说明:通过之前已经创建的目标文件File对象file来创建一个FileInputStream对象

--|public FileInputStream(String pathname) throws FileNotFoundException

参数:目标文件的路径名

异常:如果该文件不存在,或者它是一个目录,而不是一个常规文件,抑或因为其他某些原因而无法打开进行读取

说明:通过系统中真实存在的文件的路径名来创建FileInputStream对象

--|public int read() throws IOException

参数:无

异常:如果发生IO错误

返回值:下一个数据字节;如果已到达文件末尾,则返回 -1

说明:从输入流中读取一个字节,如果已至文件末尾,则方法阻塞

--|public int read(byte[] b) throws IOException

参数:预先定义好的字节数组,用来存储从输入流中读取的内容

异常:如果发生IO错误

返回值:长度值length,该长度值为从输入流中读取文件内容的长度;如果已至文件末尾,则返回-1

说明:从输入流中将最多 b.length 个字节的数据读入到一个 byte 数组中。在没有输入可用之时,此方法将阻塞。 

--|public int  read(byte[] b,int off,int len)  throws  IOException

参数:b:存储读取内容的字节数组

           off:目标数组b中的起始偏移量(也就是从字节数b的第几个位置开始写入内容,一般off为0)

           len:读取的最大字节数

异常:如果发生IO错误

返回值:返回读取的内容长度;如果已至文件末尾,则返回-1

说明:从此输入流中将最多 len个字节的数据读入一个 byte 数组中。如果len 不为 0,则在输入可用之前,该方法将阻塞;否则,不读取任何字节并返回0

--|public void close() throws IOException

参数:无

异常:如果发生IO错误

返回值:无

说明:关闭输入流,释放系统资源


FileOutputStream常用方法:

--|public FileOutputStream(String pathname)  throws FileNotFoundException

参数:输出目标文件的系统路径名称

异常:如果文件存在,但它是一个目录,而不是一个常规文件;或者该文件不存在,但无法创建它;抑或因为其他某些原因而无法打开它

返回值:无

说明:创建一个向具有指定名称的文件中写入数据的输出文件流

--|public FileOutputStream(File file)  throws FileNotFoundException

参数:为了进行写入而打开的文件

异常:如果该文件存在,但它是一个目录,而不是一个常规文件;或者该文件不存在,但无法创建它;抑或因为其他某些原因而无法打开

返回值:无

说明:创建一个向指定 File 对象表示的文件中写入数据的文件输出流

--|public void write(int b) throws IOException

参数:要写入的字节

异常:

返回值:

说明:将指定字节写入此文件输出流

--|public void write(byte[] b) throws IOException

参数:数据

异常:

返回值:

说明:将 b.length个字节从指定 byte 数组写入此文件输出流中

--|public write(byte[] b,int off,int len) throws IOException

参数:b:数据

           off:数据中的起始偏移量

           len:要写入的字节数

异常:

返回值:

说明:将指定 byte 数组中从偏移量 off 开始的 len个字节写入此文件输出流

--|public void close() throws IOException

参数:无

异常:如果发生IO错误

返回值:无

说明:关闭输出流流,释放系统资源


1.2、FileReader和FileWriter

	@Test
	public void test_Reader_Writer(){
		/*
		 * (文件复制)
		 * 读取E盘IO文件夹下test.txt文件,并将文件的内容输出到同文件夹下test1.txt文件中
		 */
		
		//1.创建File类对象
		File file = new File("E:\\IO\\test.txt");
		File file1 = new File("E:\\IO\\test3.txt");
		//2.创建输入输出流对象
		FileReader fr = null;
		FileWriter fw = null;
		try{
			fr = new FileReader(file);
			fw = new FileWriter(file1);
			//3.创建存储数据的字符数组c以及长度len
			char[] c = new char[20];
			int len;
			//4.循环遍历数组并输出复制
			while((len = fr.read(c)) != -1){
				fw.write(c,0,len);
			}
			
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			//5.关闭输入输出流
			if(fw != null){
				try {
					fw.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(fr != null){
				try {
					fr.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}



2、处理流

2.1、缓冲流(BufferedInputStream  BufferedOutPutStream   BufferedReader  BufferedWriter)

2.1.1BufferedInputStream和BufferedOutputStream

	@Test
	public void test_Buffered_In_OutputStream(){
		/*
		 * (文件复制)
		 * 读取E盘IO文件夹下test.txt文件,并将文件的内容输出到同文件夹下test1.txt文件中
		 */
		
		//1.创建File对象
		File file = new File("E:\\IO\\test.txt");
		File file1 = new File("E:\\IO\\test4.txt");
		//2.创建相应的节点流:FileInputStream、FileOutputStream
		//3.创建相应的缓冲流
		BufferedInputStream bis = null;
		BufferedOutputStream bos = null;
		try {
			FileInputStream fis = new FileInputStream(file);
			FileOutputStream fos = new FileOutputStream(file1);
			bis = new BufferedInputStream(fis);
			bos = new BufferedOutputStream(fos);
			//4.具体文件的复制
			byte[] b = new byte[20];
			int len;
			while((len = bis.read(b)) !=-1){
				bos.write(b, 0, len);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			//5.关闭缓冲流
			if(bos != null){
				try {
					bos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
				
			}
			if(bis != null){
				try {
					bis.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

2.1.2BufferedReader和BufferedWriter

	@Test
	public void test_Buffered_Reader_Writer(){
		/*
		 * (文件复制)
		 * 读取E盘IO文件夹下test.txt文件,并将文件的内容输出到同文件夹下test1.txt文件中
		 */
		//1.创建File对象
		File file = new File("E:\\IO\\test.txt");
		File file1 = new File("E:\\IO\\test6.txt");
		//2.创建相关流对象:字符输入输出流  缓冲流
		BufferedReader br = null;
		BufferedWriter bw = null;
		try {
			FileReader fr = new FileReader(file);
			FileWriter fw = new FileWriter(file1);
			br = new BufferedReader(fr);
			bw = new BufferedWriter(fw);
			String str;
			//readLine() 读取并返回文本中的一行 ;如果已至文件末尾则返回null
			while((str = br.readLine()) != null){
				bw.write(str);
				//newLine() 创建新的一行
				bw.newLine();
				//flush() 清空缓冲流中的内容
				bw.flush();
			}
		}catch (IOException e) {
			e.printStackTrace();
		}finally{
			if(bw != null){
				try {
					bw.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(br != null){
				try {
					br.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}


2.2 转换流(InputStreamReader和OutputStreamWriter)


	@Test
	public void test_InputStreamReader(){
		/*
		 * 转换流:InputStreamReader和OutputStreamWriter
		 * 解码(InputStreamReader):字节流--->字符流
		 * 编码(OutputStreamWriter):字符流--->字节流
		 *
		 * (文件复制)
		 * 读取E盘IO文件夹下test.txt文件,并将文件的内容输出到同文件夹下test1.txt文件中
		 */
		BufferedReader br = null;
		BufferedWriter bw = null;
		try {
			//解码
			File file = new File("E:\\IO\\test.txt");
			FileInputStream fis = new FileInputStream(file);
			InputStreamReader isr = new InputStreamReader(fis,"GBK");
			br = new BufferedReader(isr);
			//编码
			File file1 = new File("E:\\IO\\test7.txt");
			FileOutputStream fos = new FileOutputStream(file1);
			OutputStreamWriter osw = new OutputStreamWriter(fos,"GBK");
			bw = new BufferedWriter(osw);
			String str;
			while((str = br.readLine()) != null){
				bw.write(str);
				bw.newLine();
				bw.flush();
			}
		}catch (IOException e) {
			e.printStackTrace();
		}finally{
			if(bw != null){
				try {
					bw.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(br != null){
				try {
					br.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

2.3标准流(system.in和system.out)

	@Test
	public void test_system_In_Out(){
		/*
		 * 标准流:
		 * 输入流:system.in
		 * 输出流: systme.out
		 * 
		 * 题目:输入一串小写字符,将小写字符转换成大写输出,当遇到“e”或者“exist”
		 * 时,退出。
		 */
		
		BufferedReader br = null;
		try {
			InputStream is = System.in;
			InputStreamReader isr = new InputStreamReader(is);
			br = new BufferedReader(isr);
			String str;
			while(true){
				System.out.println("请输入字符:");
				str = br.readLine();
				if(str.equalsIgnoreCase("e") || str.equalsIgnoreCase("exsit")){
					break;
				}
				String str1 = str.toUpperCase();
				System.out.println(str1);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			if(br != null){
				try {
					br.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

2.4打印流(字节流:PrintStream  字符流:PrintWriter)

	@Test
	public void test_PrintStream(){
		/*
		 * 打印流:就是将程序中的内容输出到指定文件中
		 */
		FileOutputStream fos = null;
		try {
			fos = new FileOutputStream("print.txt");
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		//创建打印输出流,设置为自动刷新模式(写入换行符或字节“\n”时都会刷新缓冲区)
		PrintStream ps = new PrintStream(fos,true);
		//把标准输出流(控制台输出)改成文件输出
		if(ps != null){
			System.setOut(ps);
		}
		for(int i = 0; i < 255;i++){
			System.out.print((char)i);
			if((i + 1) % 5 == 0){
				System.out.println();
			}
		}
	}

2.5对象流(ObjectInputStream和ObjectOutputStream)

用于存储和读取对象的处理流。它的强大之处就是可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。

序列化(Serialize):用ObjectOutputStream类将一个Java对象写入IO流中

反序列化(Deserialize):用ObjectInputStream类从IO流中恢复该Java对象

:ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量

对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。当其它程序获取了这种二进制流,就可以恢复成原来的Java对象。序列化的好处在于可将任何实现了Serializable接口的对象转化为字节数据,使其在保存和传输时可被还原。如果需要让某个对象支持序列化机制,则必须让其类是可序列化的,为了让某个类是可序列化的,该类必须实现如下两个接口之一:Serializable,Externalizable;

:如果某个类的字段不是基本数据类型或 String  类型,而是另一个引用类型,那么这个引用类型必须是可序列化的,否则拥有该类型的 Field 的类也不能序列化

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

import org.junit.Test;

public class TestObjectStream {
	
	//对象反序列化
	@Test
	public void test_ObjectInputStream(){
		
		ObjectInputStream ois = null;
		try {
			FileInputStream fis = new FileInputStream("Student.txt");
			ois = new ObjectInputStream(fis);
			
			Student s = (Student)ois.readObject();
			System.out.println(s);
			Student s1 = (Student)ois.readObject();
			System.out.println(s1);
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			if(ois != null){
				try {
					ois.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		
	}
	
	//对象序列化
	@Test
	public void test_ObjectOutputStream(){
		Student s = new Student(1000, new Person("Bob", 18,'a'));
		Student s1 = new Student(1001, new Person("Tom",25, 'a'));
		
		ObjectOutputStream oos = null;
		try {
			FileOutputStream fos = new FileOutputStream("Student.txt");
			oos = new ObjectOutputStream(fos);
			
			oos.writeObject(s);
			oos.flush();
			oos.writeObject(s1);
			oos.flush();
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			if(oos != null){
				try {
					oos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		
	}
}

/*
 * 可序列化的对象类的特征:
 * 1.该类应该实现Serializable接口
 * 2.该类中的属性也应该是可序列化的
 */
class Student implements Serializable{
	/*
	 * 1.serialVersionUID用来表明类的不同版本间的兼容性
	 * 2.如果类没有显示定义这个静态变量,它的值是Java运行时环境根据类的内部细节自动生成的。
	 *   若类的源代码作了修改,serialVersionUID 可能发生变化。故建议,显示声明
	 * 3.显示定义serialVersionUID的用途
	 * --|希望类的不同版本对序列化兼容,因此需确保类的不同版本具有相同的serialVersionUID
	 * --|不希望类的不同版本对序列化兼容,因此需确保类的不同版本具有不同的serialVersionUID
	 */
	private static final long serialVersionUID = 1234567890;
	int number;
	Person p;

	public Student(int number,Person p){
		this.number = number;
		this.p = p;
	}

	@Override
	public String toString() {
		return "Student [number=" + number + ", p=" + p + "]";
	}
}

class Person implements Serializable{
	private static final long serialVersionUID = 109854321;
	String name;
	int age;
	char sex;
	
	public Person(String name,int age,char sex){
		this.name = name;
		this.age = age;
		this.sex = sex;
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + ", sex=" + sex + "]";
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值