Java IO流

1、概述

IO:input、output,输入输出流

  • 在这里插入图片描述

2、字节输出流OutputStream

  • public void close() :关闭此输出流并释放与此流相关联的任何系统资源。
  • public void flush() :刷新此输出流并强制任何缓冲的输出字节被写出。
  • public void write(byte[] b) :将 b.length字节从指定的字节数组写入此输出流。
  • public void write(byte[] b, int off, int len) :从指定的字节数组写入 len字节,从偏移量 off开始输 出到此输出流。
  • public abstract void write(int b) :将指定的字节输出流

2.1、FileOutputStream类

  • public FileOutputStream(File file) :创建文件输出流以写入由指定的 File对象表示的文件。
  • public FileOutputStream(String name) : 创建文件输出流以指定的名称写入文件。
    当你创建一个流对象时,必须传入一个文件路径。该路径下,如果没有这个文件,会创建该文件。如果有这个文 件,会清空这个文件的数据。
  • \r\n为换行
1)写出字节
package restudy;

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

public class demo02 {

	public static void main(String[] args) throws IOException {
		// TODO 自动生成的方法存根
		//1、创建FileOutputStream对象
//		File file = new File("a.txt");
//		FileOutputStream fos = new FileOutputStream(file);
		
		//两种创建方式都可以
		FileOutputStream fos=new FileOutputStream("a.txt");
		//2调用write方法
		fos.write(97);
		//3、用完要关闭
		fos.close();
	}

}

在这里插入图片描述

2)写出字节数组
package restudy;

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

public class demo02 {

	public static void main(String[] args) throws IOException {
		//写进字节数组
		FileOutputStream fos1=new FileOutputStream("a.txt");
		byte [] a= {97,98,99,100};
		fos1.write(a);		
		fos1.close();
		
		//指定长度
		FileOutputStream fos2 = new FileOutputStream("b.txt");
		byte [] b= "北京欢迎你".getBytes();
		fos2.write(b,2,4);//2-4,左闭右开
		fos2.close();
		
	}

}

在这里插入图片描述

3)数据追加续写
  • public FileOutputStream(File file, boolean append) : 创建文件输出流以写入由指定的 File对象表示的 文件
  • public FileOutputStream(String name, boolean append) : 创建文件输出流以指定的名称写入文件。
    这两个构造方法,参数中都需要传入一个boolean类型的值, true 表示追加数据,在原本的文本中添加字节; false 表示清空原有数据再重新创建一个文件。 这样创建的输出流对象,就可以指定是否追加续写了,

3、字节输入流 InputStream

java.io.InputStream 抽象类是表示字节输入流的所有类的超类,可以读取字节信息到内存中。它定义了字节输入 流的基本共性功能方法。
常用方法

  • public void close():关闭此输入流并释放与此流相关联的任何系统资源。
  • public int read() : 从输入流读取数据的下一个字节。返回0-255的int类型,如果没有东西可读,返回-1
  • public int read(byte[] b): 从输入流中读取一些字节数,并将它们存储到字节数组 b中 。返回读取到的有效字节个数,没有东西读取时返回-1

构造方法

  • FileInputStream(File file) : 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系 统中的 File对象 file命名。
  • FileInputStream(String name) : 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件 系统中的路径名 name命名。
1)单个读取

在这里插入图片描述

package restudy;

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

public class demo02 {

	public static void main(String[] args) throws IOException {
		// 创建文件输入流对象
		FileInputStream fileInputStream = new FileInputStream("E:\\uu\\a.txt");
		int asii;
		// 因为读不到数据就返回-1了,所以不等于-1才输出
		while ((asii = fileInputStream.read()) != -1) {
			System.out.println(asii);
		}
		fileInputStream.close();
	}

}

97
98
99
100

2)字节数组读取

在这里插入图片描述

package restudy;

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

public class demo02 {

	public static void main(String[] args) throws IOException {
		// 创建文件输入流对象
		FileInputStream fileInputStream = new FileInputStream("E:\\uu\\c.txt");
		int len;
		byte[] arr = new byte[2];
		while ((len = fileInputStream.read(arr)) != -1) {
			// 为什么要这样?因为直接输出的话,第一次AB,第二次CD,第三次ED,就不符合条件的
			System.out.println(new String(arr, 0, len));
		}
		fileInputStream.close();
	}

}

AB
CD
E

3)复制文件
package restudy;

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

public class demo02 {

	public static void main(String[] args) throws IOException {
		long start=System.currentTimeMillis();
		FileInputStream fis = new FileInputStream("E:\\uu\\p5.png");// 输入
		FileOutputStream fos = new FileOutputStream("E:\\uu\\copy_p5.png");// 输出
		byte[] b = new byte[1024];// 每次读取1024字节,增快速度
		int len;// 长度
		// copy
		while ((len = fis.read(b)) != -1) {
			fos.write(b, 0, len);
		}
		// close
		fos.close();
		fis.close();
		
		long end=System.currentTimeMillis();
		
		System.out.println("一共用了"+(end-start)+"毫秒");
	}

}

一共用了14毫秒

在这里插入图片描述

4、字符输入流 Reader

中文的GBK占2个字节,UTF-8占3个字节,但字节流只能单个字节操作,这样利用字节流来输入输出,都会把2/3个字节拆分开来,不能合在一起变中文

这是一个抽象类,不能直接用,所以只能用他的子类

java.io.Reader 抽象类是表示用于读取字符流的所有类的超类,可以读取字符信息到内存中。它定义了字符输入 流的基本共性功能方法。

  • public void close() :关闭此流并释放与此流相关联的任何系统资源。
  • public int read() : 从输入流读取一个字符。
  • public int read(char[] cbuf): 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中 。
1)FileReader类

该类是Reader类的子类
构造方法

  • FileReader(File file) : 创建一个新的 FileReader ,给定要读取的File对象。
  • FileReader(String fileName): 创建一个新的 FileReader ,给定要读取的文件的名称。
package restudy;

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

public class demo02 {

	public static void main(String[] args) throws IOException {
		FileReader fileReader = new FileReader("E:\\uu\\a.txt");
		char[] c = new char[1024];// 一次读1024字节
		int len;// 有效长度
		while ((len = fileReader.read(c)) != -1) {
			System.out.println(new String(c, 0, len));
		}

	}

}

你好haha123

在这里插入图片描述

5、字符输出流 Writer

java.io.Writer 抽象类是表示用于写出字符流的所有类的超类,将指定的字符信息写出到目的地。它定义了字节 输出流的基本共性功能方法。

  • void write(int c) 写入单个字符。
  • void write(char[] cbuf)写入字符数组。
  • abstract void write(char[] cbuf, int off, int len)写入字符数组的某一部分,off数组的开始索引,len 写的字符个数。
  • void write(String str)写入字符串。
  • void write(String str, int off, int len) 写入字符串的某一部分,off字符串的开始索引,len写的字符个 数。
  • void flush()刷新该流的缓冲。
  • void close() 关闭此流,但要先刷新它。
1)、 FileWriter类

构造方法

  • FileWriter(File file) : 创建一个新的 FileWriter,给定要读取的File对象。
  • FileWriter(String fileName) : 创建一个新的 FileWriter,给定要读取的文件的名称

字符输出流使用步骤

  • 创建 FileWriter对象,构造方法中绑定要输出数据的目的地
  • 使用 FileWriter的write方法,把数据写入到内存缓冲区中(字符转换为字节的过程)
  • 使用 FileWriter的flush,把内存缓冲区的数据刷新到文件中
  • FileWriter的close(),释放资源
package restudy;

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

public class demo02 {

	public static void main(String[] args) throws IOException {
		FileWriter fileWriter = new FileWriter("E:\\uu\\d.txt");
		fileWriter.write(97);// 写入单个字符
		fileWriter.write("\r\n");// 换行

		char[] c = { 'a', 'b' };
		fileWriter.write(c);// 写入char数组
		fileWriter.write("\r\n");

		char[] d = { '程', '序', '猿' };
		fileWriter.write(d, 0, 2);// 写入char数组中的几个元素
		fileWriter.write("\r\n");

		fileWriter.write("你好" + "\r\n");// 写入string

		String s = "北京欢迎你";
		fileWriter.write(s, 0, 3);// 写入string中的几个
		fileWriter.write("\r\n");

		fileWriter.flush();
		fileWriter.close();

	}

}

在这里插入图片描述

2)续写

续写和字节流的续写一样,只是对象名字不同而已

6、 IO异常的处理

在上面的练习中,我们都是把异常直接抛出,这样在实际开发中会被人打爆狗头,所以为了防止被打,还是用 try...catch...finally来使用比较好

package restudy;

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

public class demo02 {

	public static void main(String[] args) {
		FileWriter fileWriter = null;
		// try
		try {
			fileWriter = new FileWriter("E:\\uu\\d.txt");
			fileWriter.write(97);
		} catch (IOException e) {// catch
			e.printStackTrace();// 写异常
		} finally {// 最终不管是不是有,都会执行的代码
			try {//但是flush和close本身又有异常,又要抛出异常
				if (fileWriter != null) {
					fileWriter.flush();
					fileWriter.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

可以看到,这个用 try...catch...finally,非常麻烦,写一大堆看到头皮发麻,但是不这样写又怕被打爆狗头,所以在JDK7之后就有了方便的方法
格式:

try (创建流对象语句,相当于作用域,如果多个,使用';'隔开)
 { 
 	// 读写数据 
 } catch (IOException e) {
 	 e.printStackTrace();
  }
package restudy;

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

public class demo02 {

	public static void main(String[] args) {
		//try(xxx),括号里面写创建流对象语句,就是一个作用域
		try (FileWriter fileWriter = new FileWriter("E:\\uu\\d.txt")) {
			fileWriter.write(98);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

这样一下子就简便很多了

7、属性集 Properties

Properties 继承 Hashtable,有键与值,都是String类型
构造方法public Properties() :创建一个空的属性列表。

1)常用方法
  • public Object setProperty(String key, String value): 保存一对属性。
  • public String getProperty(String key) :使用此属性列表中指定的键搜索属性值。
  • public Set<String> stringPropertyNames() :把所有键保存到一个set类型中
  • void store(OutputStream out, String comments) :把InputStream对象写入到磁盘中,不能写入中文,String comments为注释,但注释不能输入中文(unicode)
  • void store(Writer writer, String comments) :把Writer对象写入到磁盘中,可以写入中文
  • void load(InputStream inStream) :从字节输入流(InputStream)中读取属性列表(键和元素对)。
  • void load(Reader reader) :从字符输入流(Reader)中读取属性列表(键和元素对)。
2)写入数据
  1. 创建Properties集合对象,添加数据
  2. 创建字节流/字符流对象,绑定输入目的地
  3. 使用Properties 的store方法,保存到硬盘中
  4. 释放资源
package restudy;

import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;

public class demo02 {

	public static void main(String[] args) throws IOException {
		// 创建Properties对象并赋值
		Properties properties = new Properties();
		properties.setProperty("华为", "5999");
		properties.setProperty("小米", "2999");

		FileWriter fileWriter = new FileWriter("E:\\uu\\e.txt");
		properties.store(fileWriter, "save data");
		fileWriter.close();
	}
}

在这里插入图片描述

3)读取数据
  1. 创建Properties集合对象
  2. 使用Properties的load()读取文件
  3. 遍历Properties集合

读取该文件
在这里插入图片描述

package restudy;

import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;

public class demo02 {

	public static void main(String[] args) throws IOException {
		// 创建Properties对象
		Properties properties = new Properties();
		// 准备要读取的文件
		FileReader fileWriter = new FileReader("E:\\uu\\e.txt");
		// 读取文件,然后properties就有了对应的键与值
		properties.load(fileWriter);
		// 使用stringPropertyNames(),把键值都保存到Set集合中
		Set<String> str = properties.stringPropertyNames();
		// 循环输出
		for (String string : str) {
			String value = properties.getProperty(string);
			System.out.println(string + "==>" + value);
		}
		fileWriter.close();
	}
}

华为==>5999
小米==>2999

8、缓冲流

1)字节缓冲流

字节流进阶版本,更快更强大。字节缓冲流继承字节流,所以方法函数和字节流一样,只是构造方法不一样
构造方法:

  • public BufferedInputStream(InputStream in) :创建一个 新的缓冲输入流。
  • public BufferedOutputStream(OutputStream out) : 创建一个新的缓冲输出流。

然后那些操作也是平常的那样子,什么read(),write()也是

2)字符缓冲流

构造方法:

  • public BufferedReader(Reader in) :创建一个 新的缓冲输入流。
  • public BufferedWriter(Writer out) : 创建一个新的缓冲输出流

9、转换流

众所周知,系统一开始用的是ASCII码,然后有中国加入,又产生了GBK码,后来大家统一用UTF-8或者16、32来使用,不同的码度不同的字节,读出来是不一样的,所以有个转换流

1)转换输入流
  • OutputStreamWriter(OutputStream in) : 创建一个使用默认字符集的字符流。 ,注意FileOutputStream继承OutputStreamWriter,默认为UTF-8
  • OutputStreamWriter(OutputStream in, String charsetName) : 创建一个指定字符集的字符流。charsetName为转换的码集
package restudy;

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

public class Deomo03 {

   public static void main(String[] args) throws IOException {
   	// 1.创建OutputStreamWriter对象,
   	OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("E:\\uu\\f.txt"), "UTF-8");
   	// 2.写入
   	osw.write("你好");
   	osw.flush();
   	osw.close();
   }

}

在这里插入图片描述

2)转换输出流

  • InputStreamReader(InputStream in) : 创建一个使用默认字符集的字符流。
  • InputStreamReader(InputStream in, String charsetName) : 创建一个指定字符集的字符流。
package restudy;

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

public class Deomo03 {

	public static void main(String[] args) throws IOException {
		InputStreamReader isr1 = new InputStreamReader(new FileInputStream("E:\\uu\\f.txt"), "GBK");// GBK读取
		InputStreamReader isr2 = new InputStreamReader(new FileInputStream("E:\\uu\\f.txt"), "UTF-8");// UTF-8读取

		int read;

		while ((read = isr1.read()) != -1) {
			System.out.print((char) read);
		}
		System.out.println();

		while ((read = isr2.read()) != -1) {
			System.out.print((char) read);
		}

		isr1.close();
		isr2.close();
	}

}

浣犲ソ
你好

UTF-8文件,用GBK来读取,会错误

10、序列化

Java 提供了一种对象序列化的机制。用一个字节序列可以表示一个对象,该字节序列包含该 对象的数据对象的类型对象中存储的属性等信息。字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息。 反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化。 对象的数据 、对象的类型 和 对象中 存储的数据 信息,都可以用来在内存中创建对象。看图理解序列化:

1)序列化的类:ObjectOutputStream

步骤

  1. 创建一个类,类 implements Serializable
  2. 创建ObjectOutputStream对象
  3. writeObject
  4. close

构造方法:

  • public ObjectOutputStream(OutputStream out): 创建一个指定OutputStream的ObjectOutputStream。
package restudy;

import java.io.Serializable;

public class Person implements Serializable {
	int age;
	String name;

	public Person(int age, String name) {
		this.age = age;
		this.name = name;
	}

}

package restudy;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class Deomo03 {

	public static void main(String[] args) throws IOException {
		Person person = new Person(18, "小芳");
		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:\\uu\\Person.txt"));
		oos.writeObject(person);
		oos.close();
	}

}

在这里插入图片描述
不慌,这是序列化的,直接打开是乱码的

2)反序列化:ObjectInputStream

构造方法:

  • public ObjectInputStream(InputStream in) : 创建一个指定InputStream的ObjectInputStream。
package restudy;

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

public class Deomo03 {

	public static void main(String[] args) throws IOException, ClassNotFoundException {
		ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:\\uu\\Person.txt"));
		Object o = ois.readObject();
		System.out.println(o);
		Person person = (Person) o;
		System.out.println(person);
		System.out.println(person.age + " " + person.name);
		ois.close();
	}

}

restudy.Person@9f70c54
restudy.Person@9f70c54
18 小芳

3)反序列化的一个异常

当你序列化完了,再改下对应类中的属性时,会发生错误,比如改成在这里插入图片描述
那么反序列的时候会发生错误

Exception in thread “main” java.io.InvalidClassException: restudy.Person; local class incompatible: stream classdesc serialVersionUID = 7834862679727742011, local class serialVersionUID = -8162237166348967350
at java.base/java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:689)
at java.base/java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1903)
at java.base/java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1772)
at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2060)
at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1594)
at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:430)
at test/restudy.Deomo03.main(Deomo03.java:11)

因为你序列化和反序列化的类不一样啊,都改了,但是这样还是有办法处理的

在序列化之前,在类中加上private static final long serialVersionUID = 1L;,其中,常量值随便换的,这样,就算序列了,然后改类中的东西,也能反序列出来

package restudy;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.PrintStream;

public class Deomo03 {

	public static void main(String[] args) throws IOException, ClassNotFoundException {
		System.out.println(97);// 在控制台输出
		PrintStream ps = new PrintStream("E:\\uu\\ps.txt");
		System.setOut(ps);// 输出流指向文件
		System.out.println(98);// 在文件中输出
	}

}

97

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值