java基础知识点整理(六)

1、IO流

IO流
1.什么是IO流 ?
I:input
O:output
通过IO可以完成硬盘文件的读和写。

2.IO流的分类
有多种分类方式:
一种是按照流的方向进行分类(以内存作为参照物):
往内存中去,叫做输入(input)或者叫做读(read)
从内存中出来,叫做输出(output)或者叫做写(write)

另一种方式是按照读取数据方式不同进行分类:
有的流是按照字节的方式读取数据,一次读取1个字节byte,等同于一次读取8个二进制位。这种流是万能的,什么类型的文件都可以读取,包括:文本文件、图片、声音文件、视频文件等。
例如:读取:a中国bc张三fe
第一次读:一个字节,正好读到’a’字符
第二次读:一个字节,正好读到’中’字符的一半
第三次读:一个字节,正好读到’中;字符的另外一半。
有的流是按照字符的方式读取数据,一次读取一个字符,这种流是为了方便读取普通文本文件而存在,这种流不能读取图片、声音、视频等文件。只能读取纯文本,连word文件都无法读取。
例如:假设文件file1.txt,采用字符流的话是这样读的:a中国bc张三fe
第一次读:‘a’字符(‘a’字符在wndows系统中占用1个字节)
第二次读:‘中’字符(“中”字符在windows系统中占用2个字节)

综上所述:流的分类:
输入流,输出流
字节流,字符流

3.java中的IO流都已经写好了,我们程序员不需要关心。我们最主要还是要掌握,在java中已经提供了哪些流?每个流的特点是什么?每个流对象上的常用方法有哪些?
java中所有的流都是在:java.io.*;
java中主要还是研究:
怎么new流对象
调用流对象的哪个方法是读,哪个方法是写?

4.java中IO流有四大家族:
四大家族的首领:
java.io.InputStream字节输入流
java.io.OutputStream字节输出流
java.io.Reader字符输入流
java.io.Writer字符输出流

四大家族的首领都是抽象类(abstract class)
所有流都实现了:
java.io.Closeable接口,都是可关闭的,都有close()方法。流毕竟是一个管道,这个是内存和硬盘之间的通道,用完之后一定要关闭,不然会耗费(占用)很多资源。养成好习惯,用完一定要关闭。
所有的输出流都实现了:
java.io.Flushable接口,都是可刷新的,都有flush()方法。养成一个好习惯,输出流在最终输出之后,一定要记得flush()刷新一下。这个刷新表示将通道/管道当中剩余未输出的数据强行输出完(清空管道),刷新的作用就是清空管道。
注意:如果没有flush()可能会导致丢失数据。

注:在java中只要“类名”以Stream结尾的都是字节流,以Reader/Writer结尾的都是字符流。

5.java.io包下需要掌握的流有16个:
文件流专属:
java.io.FileInputStream(掌握)
java.io.FileOutputStream(掌握)
java.io.FileReader
java.io.FileWriter

转换流(将字节流转换成字符流):
java.io.InputStreamReader
java.io.OutputStreamWriter

缓冲流专属:
java.io.BufferedReader
java.io.BufferedWriter
java.io.BufferedInputStream
java.io.BufferedOutputStream

数据流专属:
java.io.DataInputStream
java.io.DataOutputStream

标准输出流:
java.io.PrintWriter
java.io.PrintStream(掌握)

对象专属流:
java.io.ObjectInputStream(掌握)
java.io.ObjectOutputStream(掌握)

2、FileInputStream和FileOutputStream

FileInputStream:
1.文件字节输入流,万能的,任何类型的文件都可以采用这个流来读。
2.字节的方式,完成输入的操作,完成读的操作(硬盘->内存)
int read(byte[] b);一次最多读取b.length个字节
减少硬盘和内存的交互,提高程序的执行效率。

//读取文件
fils = new FileInputStream("temp.txt");
//准备一个byte数组
byte[] bytes = new byte[4];
int readCount = 0;
while((readCount = fils.read(bytes))!= -1){
	System.out.print(new String(bytes, 0, readCount));
}

FileInputStream类的其他常用方法:
int available();返回流当中剩余没有读到的字节数量
long skip(long n);跳过几个字节不读

FileOutputStream:
后面加一个true,以追加的方式在文件末尾写入,不会清空原文件内容

fils = new FileOutputStream("temp1.txt", true);

使用FileInputStream+FileOutputStream完成文件的拷贝,拷贝的过程应该是一边读一边写,使用以上的字节流拷贝文件的时候,文件类型随意,万能的,什么样的文件都能拷贝。

3、FileReader和FileWriter

FileReader:文件字符输入流,只能读取普通文本。读取文本时,比较方便、快捷。
FileWriter:文件字符输出流,写。只能输出文本。
使用FileReader和FileWriter只能拷贝普通文本文件。

4、BufferedReader和BufferedWriter

BufferedReader:
带有缓冲的字符输入流,使用这个流的时候不需要自定义char数组,或者说不需要自定义byte数组,自定义缓冲。
当一个流的构造方法中需要一个流的时候,这个被传进来的流叫做节点流
外部负责包装的这个流,叫做包装流,还有一个名字叫做处理流。
像在这个程序来说:FileReader就是一个节点流,BufferedReader就是包装流/处理流。

FileReader reader = new FileReader("Copy.java");
BufferedReader br = new BufferedReader(reader);
//读一行
String s= null;
while((s = br.readLine())!= null){
	//读取文本不带换行符
	System.out.print(s);
}
//关闭流
//对于包装流来说,只需要关闭最外层的包装流,里面的节点流会自动关闭(可以看源代码)
br.close();

BufferedWriter:带有缓冲的字符输出流。

5、DataInputStream和DataOutputStream

java.io.DataOutputStream:数据专属流
这个流可以将数据连同数据类型一并写入文件。
注意:这个文件不是普通的文本文档(这个文件使用记事本打不开)
DataInputStream:数据字节输入流
DataOutputStream写的文件,只能和DataInputStream去读,并且读的时候你需要提前知道写入的顺序,读的顺序需要和写的顺序一致,才可以正常取出数据。

6、PrintStream

java.io.PrintStream:标准输出流。默认输出到控制台。
可以改变标准输出流的输出方向吗?可以

/*
这是之前System使用过的方法、
System.gc();
System.currentTimeMilllis();
System.exit();
System.arraycopy();
*/
//标准输出流不再指向控制台,而是指向"log"文件
PrintStream printStream = new PrintStream(new FileOutputStream("log"));
//修改输出的方法
System.setOut(printStream);
//再输出
System.out.println("hello");
System.out.println("wugui");
//标准输出流不需要手动close

记录日志的方法

public static void log(String msg){
	try{
		//指向一个日志文件
		PrintStream out = new PrintStream(new FileOutputStream("log.txt",true));
		//改变输出方法
		System.setOut(out);
		//记录日期和当前时间
		Date nowTime = new Date();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
		String strTime = sdf.format(nowTime);		
	}catch(FileNotFoundException e){
		e.printStackTrace();
	}
}

7、java.io.File类

1.File类和四大家族没有关系,所以File类不能完成文件的读写。
2.File对象代表什么?
文件和目录路径名的抽象表示形式
F:\IDEAtest这是一个File对象
F:\IDEAtest\temp.txt也是File对象
一个File对象有可能对应的是目录,也可能是文件
File只是一个路径名的抽象表现形式。
3.需要掌握File类中常用的方法

//创建一个File对象
File f1 = new File("F:\\IDEAtest\\temp");
//判断是否存在
f1.exists();
//以文件形式创建出来
f1.createNewFile();
//以目录的形式创建出来,
f1.mkdir();//创建多个目录用mkdirs()
//获取文件的父路径
f1.getParent();
//获取文件的绝对路径
f1.getAbsolutePath();
//获取文件名
f1.getName();
//判断是否是一个目录
f1.isDireactory();
//判断是否是一个文件
f1.isFile();
//获取文件最后一次修改的时间
long haoMiao = f1.lastModified();
//将总毫秒数转换成日期
Date time = new Date(haoMiao);
//日期格式化
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
String strTime = sdf.format(time);
System.out.println(strTime);
//获取文件的大小
System.out.println(f1.length());
//File中listFiles方法
//获取当前目录下的所有子文件
File f = new File("F:\\IDEAtest");
File[] file=f.listFile();

8、序列化和反序列化

序列化和反序列化
重点:
参与序列化的类型必须实现java.io.Serializable接口。
并且建议将序列化版本号手动的写出:
private static final long serialVersionUID = 18236929999L;

1.java.io.NotSerializableException异常
表示某个对象不支持序列化。
2.参与序列化和反序列化的对象,必须实现Serializable接口。
3.注意:通过源代码发现,Serializable接口只是一个标识接口:
public interface Serializable{}
这个接口当中什么代码都没有,那么它起到一个什么用呢?
起到标识的作用,标志的作用,java虚拟机看到这个类实现了这个接口,可能会对这个类进行特殊待遇。
Serializable这个标志接口是给java虚拟机参考的,java虚拟机看到这个接口之后,会为该类自动生成一个序列化的版本号。
4.序列化版本号有什么用?
java.io.InvalidClassException:
com.bjpowernode.javase.test.ObjectTest.Student;
local class incompatible:
stream classdesc serialVersionUID = -1782634778(十年后)
local class serialVersionUID = -8939388844(十年前)
java语言中是采用什么机制来区分类的?
第一:首先通过类名进行比对,如果类名 不一样,肯定不是同一个类。
第二:如果类名一样,再怎么进行类的区分?靠序列版本号进行区分。
举例:
小鹏编写了一个类:com.bjpowernode.javase.test1.ObjectTest.Student implement Serializable
胡浪编写了一个类
com.bjpowernode.javase.test1.ObjectTest.Student implement Serializable
不同的人编写了同一个类,但是这“两个类确实不是同一个类”。这个时候序列化版本号就起上作用了。对于java虚拟机来说,java虚拟机是可以区分开着两个类的,因为这两个类都实现了Serializable接口,都有默认的序列化版本号,它们的序列化版本号不一样,所以区分开了。(这是自动生成序列化版本号的好处)
请思考:这种自动生成序列化版本号有什么缺陷?
这种自动生成的序列化版本号的缺点是:一旦代码确定之后,不能进行后续的修改,因为只要修改,必然会重新编译,此时会生成全新的序列化版本号,这个时候java虚拟机会认为这是一个全新的类。(这样就不好了!)
最终结论:
凡是一个类实现了Serializable接口,建议给类提供一个固定不变的序列化版本号。这样,以后这个类即使修改了,但是版本号不变,java虚拟机会 认为是同一个类。

5.可以一次序列化多个对象吗?
可以,可以将对象放到集合当中,序列化集合。
提示:
参与序列化的ArrayList集合以及集合中的元素User 都需要实现java.io.Serializable接口

List<User> userList = new ArrayList<>();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("users"));
//一次序列化一个集合,这个集合对象中放了很多其他对象
oos.writeObject(userList);

9、IO+Properties联合使用

IO流:文件的读和写
Properties:是一个Map集合,key和value都是String类型。
IO+Properties的联合使用,是一个非常好的设计理念:
以后经常修改的数据,可以单独写到一个文件中,使用程序动态读取。将来只需要修改这个文件的内容,java代码不需要修改,不需要重写编译,服务器也不需要重写启动。就可以拿到动态的信息。
类似于以上机制的这种文件被称为配置文件。
并且当配置文件中的内容格式是:
key1=value1
key2=value2
的时候,我们把这种配置文件叫做属性配置文件

java规范中要求:属性配置文件建议以.properties结尾,但不是必须的。这种以.properties结尾的文件在java中被称为:属性配置文件。其中Properties是专门存放属性配置文件内容的一个类。

Properties是一个Map集合,key和value都是String类型。
想将userinfo文件中的数据加载到Properties对象当中。

//新建一个输入流对象
FileReader reader = new FileReader("userinfo");
//新建一个Map对象
Properties pro= new Properties();
//调用Properties对象的load方法将文件中的数据加载到Map集合中
//文件中数据顺着管道加载到Map集合中,其中等号左边做key,等号右边做value
pro.load(reader);
//通过key来获取value
String username = pro.getProperty("username");
System.out.println(username);
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值