一、IO流分类方式:
1. 按照流的方向进行分类:
以内存作为参照物,往内存中去,叫做输入(Input)。或者叫做读(Read)。从内存中出来,叫做输出(Output)。或者叫做写(Write)。
2. 按照读取数据方式不同进行分类:
- 按照字节的方式读取数据,一次读取1个字节byte,等同于一次读取8个二进制位。这种流是万能的,什么类型的文件都可以读取。包括:文本文件,图片,声音文件,视频文件等…
- 按照字符的方式读取数据的,一次读取一个字符,这种流是为了方便读取普通文本文件而存在的,这种流不能读取:图片、声音、视频等文件。只能读取纯文本文件,连word文件都无法读取。
假设文件file1.txt ,a中国bc张三fe
采用字节流的话是这样读的:
第一次读:一个字节,正好读到’a’
第二次读:一个字节,正好读到’中’字符的一半。
第三次读:一个字节,正好读到’中’字符的另外一半。
采用字符流的话是这样读的:
第一次读:'a’字符('a’字符在windows系统中占用1个字节。)
第二次读:'中’字符('中’字符在windows系统中占用2个字节。)
二、常用IO流及其方法
1、 四大家族流(abstract class)
- 四大流
- 字节输入流 java.io.InputStream
- 字节输出流 java.io.OutputStream
- 字符输入流 java.io.Reader
- 字符输出流 java.io.Writer
(ps:根据结尾区分,InputStreamReader是字符输入流) - 所有的流都实现了:java.io.Closeable接口,都是可关闭的,都有close()方法。流毕竟是一个管道,这个是内存和硬盘之间的通道,用完之后一定要关闭,不然会耗费(占用)很多资源。
- 所有的输出流都实现了:java.io.Flushable接口,都是可刷新的,都有flush()方法。养成一个好习惯,输出流在最终输出之后,一定要记得flush()刷新一下。这个刷新表示将通道/管道当中剩余未输出的数据强行输出完(清空管道!)刷新的作用就是清空管道。注意:如果没有flush()可能会导致丢失数据。
2、常用的流
- 文件专属:
- java.io.FileInputStream(掌握)
- java.io.FileOutputStream(掌握)
- java.io.FileReader
- java.io.FileWriter
- FileInputStream的常用方法:
- read()方法:返回值是字节本身。
- read(byte[]b)方法:一次最多读取b.length个字节。返回值是读到的字节数量。没有读到字节的话返回值-1。减少内存和硬盘的交互,提高程序执行的效率。
- int available():返回还剩可以读的字节数
- long skip(long n):跳过几个字节不读取
范例:(如何读取及输出)
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
/**
* FileInputStream用byte数组接收最终版
*/
public class FileInputStreamTest04 {
public static void main(String[] args) {
FileInputStream file = null;
try {
file = new FileInputStream("E:\\JavaSE\\temp\\temp.txt");
//准备一个byte数组
byte [] bytes = new byte[4];
//准备一个变量用来接收读到的字节数
int i = 0;
while((i=file.read(bytes))!=-1){
//把byte数组转换成字符串输出
System.out.println(new String (bytes,0,i));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
if(file!=null){
try {
file.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
- FileOutputStream的常用方法:
- 构造方法:
FileOutputStream(String name) :传入一个文件名,如果不存在会新建,如果存在会将其内容清空重新写入
FileOutputStream(String name, boolean append): 传入一个文件名和true,则从文件末尾处开始写
FileOutputStream(File file);
- 方法摘要:
write(byte [] b):
write(byte [] b ,int off,int length):
- 转换流:(将字节流转换成字符流)
- java.io.InputStreamReader
- java.io.OutputStreamWriter
范例:
FileInputStream file = new FileInputStream("some.txt");
InputStreamReader in = new InputStreamReader(file);
BufferedReader br = new BufferedReader(in);
- 缓冲流专属:带有缓冲区的字符输入流,不需要定义byte数组或者char数组。
- java.io.BufferedReader:
BufferedReader(Reader in):传进去的流称为节点流,外部流称为包装流
bufferedreader.readLine()方法:每次读一行(不包括换行)
范例:
import java.io.BufferedReader;
import java.io.FileReader;
public class BufferedReaderTest01 {
public static void main(String[] args) throws Exception{
FileReader file = new FileReader("some.txt");
BufferedReader br = new BufferedReader(file);
String s = null;
while((s=br.readLine())!=null){
System.out.println(s);
}
br.close();//关闭最外层即可
}
}
-
java.io.BufferedWriter
-
java.io.BufferedInputStream
-
java.io.BufferedOutputStream
-
数据流专属:
DataOutputStream写的文件,只能用DataInputStream去读,并且读和写的顺序要一致。
-
java.io.DataInputStream
-
java.io.DataOutputStream
-
标准输出流:
-
java.io.PrintWriter
-
java.io.PrintStream(掌握)
System.out生成的是一个PrintStram类
标准输出流默认输出到控制台,可以改变指向,用setOut()方法
标准输出流不需要手动close()关闭
范例:
//标准输出流不再指向控制台,指向"today"文件
PrintStream ps =new PrintStream(new FileOutputStream("today"));
System.setOut(ps);
- 对象专属流:
- java.io.ObjectInputStream(掌握)
- java.io.ObjectOutputStream(掌握)
对象的序列化和反序列化
Serialize:将JAVA对象存储到硬盘上,将JAVA对象保存下来。
DeSerialize:将硬盘上的数据重新恢复到内存上,恢复成JAVA对象。
参与序列化和反序列化的对象必须实现Serializable接口,这是个标志借口,里面代码什么都没有。JVM看到Seriazable接口后会自动生成一个序列化版本号,用来区分类。自动生成的序列号的缺点:一旦代码被修改,版本号也变了,运行错误。
建议实现Serializable接口后,也手动生成序列化版本号。private static final long serialVersionUID = 1L;
transient关键字:不参与序列化
public interface Serializable {
}
-
序列化单个对象:
创建ObjectOutputStream对象;创建需要序列化的对象(实现Serializable接口);调用writeObject()方法将该对象写入文件中。 -
反序列化单个对象:
创建ObjectInputStream对象;调用readObject()方法(返回值类型为Object);输出obj。 -
序列化多个对象:
创建ObjectOutputStream对象;创建一个List集合,泛型为要序列化的对象类型;创建多个对象并add()到List集合中;调用writeObject()方法将List集合写入文件。
public class ObjectOutputStreamTest {
public static void main(String[] args) throws Exception{
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("Black"));
//序列化多个对象
List<Student> list = new ArrayList<>();
Student st1 = new Student(1,"Emma" );
Student st2 = new Student(2,"Rena");
list.add(st1);
list.add(st2);
out.writeObject(list);
out.flush();
out.close();
}
}
class Student implements Serializable {
private int id;
private String name;
public Student(int id, String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
- 反序列化多个对象:
创建ObjectInputStream对象;调用readObject()方法(返回值类型为对象类型,向下转型);foreach循环输出对象。
public class ObjectInputStreamTest {
public static void main(String[] args) throws Exception{
//反序列化多个对象
ObjectInputStream in= new ObjectInputStream(new FileInputStream("Black"));
//向下转型
List<Student> list = (List<Student>)in.readObject();
for(Student ss :list){
System.out.println(ss);
}
in.close();
}
}
输出结果:
Student{id=1, name=‘Emma’}
Student{id=2, name=‘Rena’}
三、File类:
文件或者目录路径名
1、构造方法:
File(String pathname)
2、常用方法:
返回值类型 | 方法名 |
---|---|
boolean | exists(); |
boolean | creatNewFile:不存在时,以文件的形式创建 |
boolean | mkdir:以目录的形式创建 |
boolean | mkdirs:以目录的形式创建 (包括所有父目录) |
String | getParent();返回当前路径的父路径名字符串,如果没有,返回null |
File | getParentFile() ;返回当前路径的父路径名,如果没有,返回null |
String | getAbsolutePath();返回绝对路径名字符串 |
File | File getAbsoluteFile();返回绝对路径名形式 |
Sring | getName();返回当前路径表示的文件或目录的名称 |
boolean | isDirectory();测试此抽象路径名表示的文件是否是一个目录。 |
boolean | isFile();测试此抽象路径名表示的文件是否是一个标准文件 |
Long | lastModified();返回文件的最后一次修改时间,返回值为从1970到修改时间的毫秒数 |
long | length();返回此抽象路径名表示的文件的大小 |
File[] | listFiles();返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件 |
四、IO+Properties配置文件
以后经常改变的数据,可以单独写到一个文件中,使用程序动态读取。将来只需要修改这个文件的内容,java代码不需要改动,不需要重新编译,服务器也不需要重启。就可以拿到动态的信息。
类似于以上机制的这种文件被称为配置文件。
并且当配置文件中的内容格式是:
key1=value
key2=value 的时候,我们把这种配置文件叫做属性配置文件。
Java规范中有要求:属性配置文件建议以.properties结尾,但这不是必须的。其中Properties是专门存放属性配置文件内容的一个类。
public class IOPropertiesTest {
public static void main(String[] args) throws Exception {
//新建一个输入流对象
FileReader Re = new FileReader("exercise04\\user.properties");
//新建一个Map集合
Properties pro = new Properties();
//调用Properties的load方法将文件的数据加载到Map集合中
pro.load(Re);
//通过key获取value
System.out.println(pro.getProperty("password"));
}
}
属性配置文件的key重复的话,value会自动覆盖