总结


以下需要重点掌握:

  • 字节流,以下读取结束全部返回-1

    • 字节节点流-访问文件 FileInputStream/FileOutputStream

      • 可以读取任意文件
      • 可以复制图片
      • 读取字符String类型会乱码
    • 字节处理流-缓冲流 BufferedInputStream/BufferedOutputStream
      • 需要节点流作为入参,即字节的访问文件流
      • 写入文件时,需要调用flush()方法,才能写入文件中
    • 字节处理流-对象流(类) ObjectInputStream/ObjectOutputStream
      • 对对象进行序列化和反序列化
      • 序列化:对象输出流,将数据写入文件中
      • 反序列化:对象输入流,将文件中的数据写入内存磁盘中
      • 需要节点流作为入参,即字节的访问文件流
      • 可以通过集合来序列化或反序列化多个对象
      • 序列化和反序列化的对象需要继承Serializable接口
    • 字节处理流-打印流PrintStream
    • 字节处理流-转换流InputStreamReader/OutputStreamWriter
      • 将字节流转换成字符流
      • 可以选择转换成字符流的编码格式
      • 需要将字节访问文件作为节点流
  • 字符流
    • 字符节点流-访问文件FileReader/FileWriter

      • 读取结束返回null
      • 可以复制,写入字符
      • 不能复制图片
    • 字符处理流-缓冲流BufferedReader/BufferedWriter
      • 读取结束返回-1
      • 字符缓冲输入流支持一行一行读取到内存,使用方法readLine()
      • 字符缓冲输出流支持使用newLine()的方法进行换行,其它字符流换行都是“\r\n”
      • 需要将字符节点流-访问文件作为节点流,进行入参
    • 字符处理流-打印流 PrintWriter 
      • 常用于日志生成
流知识点总结(按照单位分类)
   字节流 字符流
分类 字节输入流 字节输出流 字符输入流 字符输出流
抽象基类 抽象基类 InputStream OutputStream Reader Writer
节点流 访问文件 FileInputStream FileOutputStream FileReader FileWriter
处理流 访问数组 ByteArrayInputStream ByteArrayOutputStream CharArrayReader CharArrayWriter
访问管道 PipedInputStream PipedOutputStream PipedReader PipedWriter
访问字符串     StringReader StringWriter
缓冲流 BufferedInputStream BufferedOutputStream BufferedReader BufferedWriter
转换流 InputStreamReader OutputStreamWriter    
对象流(类) ObjectInputStream ObjectOutputStream    
对象流(文件) FileInputStream FileOutputStream FileReader FileWriter
打印流   PrintStream   PrintWriter
退回输入流 PushbackInputStream   PushbackReader  
特殊流 DataInputStream DataOutputStream    
备注:蓝底的均为需要相对应的节点流,进行入参

概述


流的概念

  • 概念:内存与存储设备之间传输数据的通道。

  • 水借助管道传输;数据借助流传输。


流的分类

按方向【重点】

  • 输入流:将<存储设备>中的内容读入到<内存>中。
  • 输出流:将<内存>中的内容写入到<存储设备>中。

按单位

  • 字节流:以字节为单位,可以读写所有数据。
  • 字符流:以字符为单位,只能读写文本数据。

按功能

  • 字节流:具有实际传输数据的读写功能。
  • 过滤流:在节点流的基础之上增强功能。

下面将根据单位类型:字节流、字符流,对I/O框架进行概述


字节流

字节流的父类(抽象类)

  • InputStream字节输入流

    • public int read(){}
    • public int read(byte[] b){}
    • public int read(byte[] b,int off,int len){}
  • OutputStream字节输出流
    • public void write(int n){}
    • public void write(byte[] b){}
    • public void write(byte[] b,int off,int len){}

字节流的子类

文件字节流

  • FileInputStream

    • 构造方法

      • String:以路径的方式初始一个输入流;常用;比如:“D://javaTest.txt”
      • File:以File实例初始一个输入流 ;比如:new File(“D://javaTest.txt”)
      • FileDescriptor:以FileDescriptor实例初始一个输入流,FileDescriptor是一个文件描写叙述符;使用的fdObj文件描述符来作为参数,文件描述符是指与计算机系统中的文件的连接,前面两个方法的源码中最后都是利用文件描述符来建立连接的

    • read方法重载

      • public int read()//从输入流中读取一个字节数据,返回读到的字节数据,如果达到文件末尾,返回-1。
      • public int read(byte[] b)//从输入流中读取字节数组长度的字节数据存入数组中,返回实际读到的字节数;如果达到文件的尾部,则返回-1。

  • FileOutputStream构造方法

    • File、String:通过file对象或者文件路径来创建文件流bu;从文件头写入文件
    • File,boolean、String,boolean:创建文件流形式同上;当boolean为true时,对文件的写入为“追加数据”,当boolean为false时,对文件的写入为“覆盖原有数据”
    • FileDescriptor:使用的fdObj文件描述符来作为参数,来创建文件流

    • write方法重载

      • public void write(int b)//将指定字节写入输出流。
      • public void write(bute[] b)//一次写多个字节,将b数组中所有字节,写入输出流。
 1 /**
2 * 演示文件字节输入流的使用
3 * FileInputStream
4 */
5 public class Demo01 {
6 public static void main(String[] args) throws Exception{
7 //1.创建FileInputStream,并指定文件路径
8 FileInputStream fis = new FileInputStream("D://javaText.txt");//文件内容为:a-z26个英文字母
9
10 //2.读取文件
11 //2.1 read()读取单个字节,一个字节一个字节读
12 /*
13 int data = fis.read();
14 System.out.println((char) data);//强转成char类型,默认的是ASCLL编码格式
15 while ((data=fis.read()) != -1) { //通过循环一个字节一个字节获取全文内容,赋值给data
16 System.out.println((char) data);
17 }
18 */
19 //2.2 read(byte[] b);读取多个字节
20 //2.2.1 数组空间大于文件内容时,直接放
21 /*
22 byte[] b = new byte[1024];
23 int count=fis.read(b);//计数
24 System.out.println(count);
25 System.out.println(new String(b));
26 */
27 //2.2.2 数组空间小于文件内容时,使用循环去获取
28 byte[] b =new byte[2];
29 int count =0;
30 while ((count=fis.read(b))!=-1){ //fis.read读取的内容放到b中,读取结束后,fis.read赋给计数参数count的值为-1
31 System.out.println(new String(b,0,count));//从0开始到count为-1之间,打印b中的字符串内容
32 }
33
34 //3.关闭流
35 fis.close();
36 }
37 }
 1 /**
2 * 演示文件字节输出流的使用
3 * FileOutputStream
4 */
5 public class Demo02 {
6 public static void main(String[] args) throws Exception {
7 //1.创建文件输出流对象,没有文件的会自动生成
8 FileOutputStream fos = new FileOutputStream("D://javaText2.txt",true); //为true,不覆盖原文件内容,不断追加
9
10 //2.输出流,文件中写入数据
11 //2.1 一个字节一个字节写入
12 fos.write(97);//数字代表的时ASCLL码对应的字符,97对应的是小写的a
13 fos.write('b');
14 fos.write('c');
15 fos.write(66);
16 //2.2 通过字符串写入
17 String string = "helloworld";
18 fos.write(string.getBytes());
19
20 //3.关闭输出流
21 fos.close();
22
23
24 }
25 }

文件字节流案例-复制操作

 1 /**
2 * 使用文件字节流复制文件
3 */
4 public class Demo03 {
5 public static void main(String[] args) throws Exception{
6 //创建输入流,输入到内存
7 FileInputStream fis = new FileInputStream("D://test01.png");
8 //创建输出流,输出到硬盘/文件
9 FileOutputStream fos = new FileOutputStream("D://test02.png");
10
11 int count;//保存一次实际读取的个数
12 byte[] b = new byte[1024];
13
14 while ((count=fis.read(b))!=-1){ //读取文件信息,存储到数组b中,当读取结束即计数cout=-1时,结束while循环
15 fos.write(b,0,count); //将数组b从0开始到-1的,写入到fos对象的文件中
16 }
17
18 //关闭流
19 fis.close();
20 fos.close();
21
22 }
23 }

字节缓冲流

  • 缓冲流:BufferedInputStream/BufferedOutputStream

    • 提高IO效率,减少访问磁盘的次数;
    • 数据存储在缓冲区中。flush可以将缓存区的内容写入文件,也可以直接close。
 1 /**
2 * 使用字节缓冲流读取
3 * BufferedInputStream
4 */
5 public class Demo04 {
6 public static void main(String[] args) throws Exception{
7 //使用该输入流每次会从硬盘读入
8 FileInputStream fis = new FileInputStream("D://javaText.txt");
9 //缓冲流需要一个底层流
10 //缓冲流每次从缓冲区读取
11 BufferedInputStream bis = new BufferedInputStream(fis);
12
13 //读取
14 /*
15 int data;
16 while ((data=bis.read())!=-1){
17 System.out.println((char)data);
18 }
19 */
20
21 //我们也可以自己创建一个缓冲区;
22 //每次读取从自己创建的缓冲区中读取。
23 int count;
24 byte[] bytes = new byte[2];
25 while ((count=bis.read(bytes,0,bytes.length))!=-1){
26 System.out.println(new String(bytes,0,count));
27 }
28
29 bis.close();
30 }
31 }
 1 /**
2 * 使用字节缓冲流写入文件
3 * BufferedOutputStream
4 */
5 public class Demo05 {
6 public static void main(String[] args) throws Exception{
7 //缓冲流将数据写入到缓冲区
8 FileOutputStream fos = new FileOutputStream("D://javaText2.txt",true);
9 BufferedOutputStream bos = new BufferedOutputStream(fos);
10
11 //写入文件
12 String string = "Hello World";
13 bos.write(string.getBytes());
14 bos.write(" Hello Java".getBytes());
15
16 bos.flush();//相当于刷新,提交的功能
17 //最后close其实内部也会调用flush
18 bos.close();
19 }
20 }
 1 /*
2 *使用字节缓冲区进行复制操作
3 */
4 public class Demo06 {
5 public static void main(String[] args) throws Exception{
6
7 //创建缓存区-输入流底层流
8 FileInputStream fis = new FileInputStream("D://test01.png");
9 //创建缓存区输入流
10 BufferedInputStream bis = new BufferedInputStream(fis);
11 //创建缓存区-输出流底层流
12 FileOutputStream fos = new FileOutputStream("D://test02.png");
13 //创建缓冲区输出流
14 BufferedOutputStream bos = new BufferedOutputStream(fos);
15 //声明计数变量
16 int count;
17 //bytes存储数据
18 byte[] bytes = new byte[1024];
19 while ((count=bis.read(bytes,0,bytes.length))!=-1){//缓存输入流读取数据存到数组中,当读取结束,bis.read返回-1,退出循环
20 bos.write(bytes,0,count);//缓存输出流写入数据到文件中,从0-cont
21 }
22 bos.close();
23 bis.close();
24 }
25 }

对象流

  • 对象流:ObjectOutputStream/ObjectInputStream

    • 增加了缓冲区功能。
    • 增强了读写8种基本数据类型和字符串功能。
    • 增强了读写对象的功能:
      • readObject()//从流中读取一个对象。反序列化
      • writeObject(Object obj)向流中写入一个对象。序列化

    使用流传输对象的过程称为序列化、反序列化。

    • 序列化:内存将对象写入文件中
    • 反序列化:将文件中对象读到内存中

序列化

 1 /**
2 * 学生类
3 */
4 public class Student {
5 private String name;
6 private int age;
7
8 public Student(String name, int age) {
9 this.name = name;
10 this.age = age;
11 }
12
13 public String getName() {
14 return name;
15 }
16
17 public void setName(String name) {
18 this.name = name;
19 }
20
21 public int getAge() {
22 return age;
23 }
24
25 public void setAge(int age) {
26 this.age = age;
27 }
28
29 @Override
30 public String toString() {
31 return "Student{" +
32 "name='" + name + '\'' +
33 ", age=" + age +
34 '}';
35 }
36 }
 1 /**
2 * 使用ObjectOutputStream实现对象的序列化
3 * 注:序列化的类必要要实现Serializable接口
4 */
5 public class Demo07 {
6 public static void main(String[] args) throws Exception{
7 //1.创建对象流
8 //1.1 创建对象流底层流,基于FileOutputStream
9 FileOutputStream fos = new FileOutputStream("D://stu.bin");
10 //1.2 创建对象流,fos为入参
11 ObjectOutputStream oos = new ObjectOutputStream(fos);
12
13 //2.序列化(写入操作)
14 Student student = new Student("张三",20);
15 oos.writeObject(student);
16
17 //3.关闭
18 oos.close();
19 System.out.println("序列化完毕");
20 }
21 }

注:执行上述代码后IDE会抛出java.io.NotSerializableException,意思是Student类不能被序列化,需要实现Serializable接口。

1 //不需要实现任何方法,标记作用
2 public class Student implements Serializable {}

Serializable其实是一个标志接口,用来标志该类是否可以被序列化。我们进到该接口的源码可以发现里面不含任何属性和抽象方法。

1 public interface Serializable {}

反序列化

 1 /**
2 * 使用ObjectInputStream实现反序列化(读取重构对象)
3 */
4 public class Demo08 {
5 public static void main(String[] args) throws Exception{
6 //1.创建对象流
7 //1.1 创建对象流节点流,即底层流
8 FileInputStream fis = new FileInputStream("D://stu.bin");
9 //1.2 创建对象流,fis入参
10 ObjectInputStream ois = new ObjectInputStream(fis);
11
12 //2.读取文件,定义参数student来接这个读取的内容,读取的内容是Student类型,所以需要强制转换
13 Student student = (Student) ois.readObject();
14
15 //3.关闭
16 ois.close();
17 System.out.println("执行完毕");
18 System.out.println(student.toString());
19
20 }
21 }

序列化和反序列化注意事项

  序列化类必须实现Serializable接口,前文已经说过。

  序列化类中的对象属性也要求实现Serializable接口。也就是说如果Student类中有一个Grad引用类型的属性private Grad info;那么Grad这个类也要实现Serializable接口。

  序列化类中可以添加序列化版本号ID,以保证序列化的类和被序列化的类是同一个类。在上面的代码中我并没有添加序列号版本,虽然IDE没有报错,但是会显示一个警告,提示我添加序列化版本号(串行版本标识)。我们可以在Student类中添加:

1 private static final long serialVersionUID = 66666L;
  • 此时再运行Demo8就会报一个无效类的异常:

  • 意思就是两个类的serialVersionUID不一样。可以看到之前虽然没有显式添加序列版本号,但它已经自动生成了一个。我们再运行一下Demo7序列化,再运行Demo8反序列化就可以正常执行了。

  使用transient(短暂的)修饰属性,可以避免该属性被序列化。用它来修饰age:

1 private transient int age;
  • 把student这个对象序列化后再反序列化,这个对象的age属性就变成了0。

  静态属性 static 不能被序列化。

  可以利用集合来序列化多个对象:

 1 /**
2 * 使用ObjectOutputStream实现对象的序列化
3 * 注:序列化的类必要要实现Serializable接口
4 */
5 public class Demo07 {
6
7 public static void main(String[] args) throws Exception{
8 //1.创建对象流
9 //1.1 创建对象流底层流,基于FileOutputStream
10 FileOutputStream fos = new FileOutputStream("D://stu.bin");
11 //1.2 创建对象流,fos为入参
12 ObjectOutputStream oos = new ObjectOutputStream(fos);
13
14 //2.序列化(写入操作)
15 Student s1 = new Student("张三",20);
16 Student s2 = new Student("李四",20);
17
18 //使用集合来接对象
19 ArrayList<Student> student = new ArrayList<>();
20 student.add(s1);
21 student.add(s2);
22 oos.writeObject(student);
23
24 //3.关闭
25 oos.close();
26 System.out.println("序列化完毕");
27 }
28 }
 1 /**
2 * 使用ObjectInputStream实现反序列化(读取重构对象)
3 */
4 public class Demo08 {
5 public static void main(String[] args) throws Exception{
6 //1.创建对象流
7 //1.1 创建对象流节点流,即底层流
8 FileInputStream fis = new FileInputStream("D://stu.bin");
9 //1.2 创建对象流,fis入参
10 ObjectInputStream ois = new ObjectInputStream(fis);
11
12 //2.读取文件
13 ArrayList<Student> list =(ArrayList<Student>) ois.readObject();
14
15 //3.关闭
16 ois.close();
17 System.out.println("执行完毕");
18 System.out.println(list.toString());
19
20 //4.遍历集合里面的对象
21 ListIterator<Student> studentListIterator = list.listIterator();
22 while (studentListIterator.hasNext()){
23 System.out.println(studentListIterator.next());
24 }
25 }
26 }


编码方式

  • IOS-8859-1

    收录除ASCII外,还包括西欧、希腊语、泰语、阿拉伯语、希伯来语对应的文字符号。采用1个字节来表示,最多只能表示256个字符。

  • UTF-8

    针对Unicode码表的可变长度字符编码。国际上使用的编码,也称为“万国码”,收录了几乎所有国家的常用字符。采用1至3个字节来表示一个字符。

  • GB2312

    简体中文,采用1个或2个字节来表示字符,95年之前所采用的编码。

  • GBK

    简体中文的扩充,GB2312的升级版本。

  • BIG5

    台湾,繁体中文。

当编码方式和解码方式不一致时,会出现乱码。假如Demo1中的文件内容不是字母而是“我爱中国”这样的汉字,那么读取出来的信息就是乱码。因为字节流按字节输入输出,而这四个汉字占了12个字节,把一个汉字按一个一个字节读入自然会出现问题,这时就需要使用字符流。


字符流

字符流的父类(抽象类)

  • Reader:字符输入流

    • public int read()

      从流中读取单个字符,用整型来返回读取的字符;当读到流底部时返回-1。

    • public int read(char[] c)

      从流中读取字符保存到c数组中,返回读取的字符个数,当读到流底部时返回-1。

    • public int read(char[] cbuf,int off,int len){}

      抽象方法。

  • Writer:字符输出流

    • public void write(int n)

      写入单个字符,只能写入包含16位低阶字节的整型数值,16位高阶字节将会被忽略。

    • public void write(String str)

      写入一个字符串。

    • public void write(char[] cbuf)

      写入一个字符数组。

字符流的子类

  • FileReader:

    • public int read()

      继承自InputStreamReader类。读取单个字符,返回读取的字符,当读到流底部时返回-1。

    • public int read(char[] c)

      继承自Reader类。

    • public int read(char[] cbuf,int offset,int length)

      继承自InputStreamReader类。从流中读取部分字符到cbuf中指定位置,返回读取到的字符个数,当读到流底部时返回-1。

 1 /*
2 *使用FileReader读取文件
3 */
4 public class Demo01 {
5 public static void main(String[] args) throws Exception{
6 //1.创建FileReader 文件字符输入流
7 //文件内容为:好好学习,天天向上Hello World
8 FileReader fr = new FileReader("D://javaText.txt");
9
10 //2.读取
11 //2.1 单字节读取
12 /*
13 int count;
14 while ((count=fr.read())!=-1){
15 System.out.println((char)count);
16 }
17 */
18
19 //2.2 多个字节读取
20 char[] bytes = new char[4];
21 int conut;
22 while ((conut=fr.read(bytes,0,bytes.length))!=-1){
23 System.out.println(new String(bytes,0,conut));
24 }
25
26 //3. 关闭
27 fr.close();
28 }
29 }

这里可能会遇到的一个问题:

上述代码执行后理应是正常输出一段文字,但是出现了文字乱码。打开JDK API查看FileReader类的描述:

Convenience class for reading character files. The constructors of this class assume that the default character encoding and the default byte-buffer size are appropriate. To specify these values yourself, construct an InputStreamReader on a FileInputStream.

大意就是该类的构造方法有一个默认的字符编码格式和一个默认字节缓冲区,并没有指明这个编码格式就是UTF-8。查看系统默认编码,打开CMD输入chcp,得到一个值为936的活动编码页,通过查询得知该代码页所对应的国家(地区)或语言为:中国 - 简体中文(GB2312)。这与本地所保存的文本编码UTF-8不一致,所以导致了文字乱码的出现。而要指定编码格式需要创建一个InputStreamReader或FileInputStream对象使用其构造方法。

如果遇到上述报错,以下是能正常运行的代码:

 1 public class Demo1 {
2 public static void main(String[] args) throws IOException {
3 //指定编码格式
4 InputStreamReader inputStreamReader=new InputStreamReader(new FileInputStream("D://javaText.txt"),"UTF-8");
5 int data;
6 while((data=inputStreamReader.read())!=-1) {
7 System.out.print((char)data);
8 }
9 inputStreamReader.close();
10 }
11 }

  • FileWriter:

    • public void write(int c)

      继承自OutputStreamWriter类,写入一个字符。

    • public void write(String str)

      继承自Writer类。

    • public void Write(char[] cbuf)

      继承自Writer类。

 1 /**
2 * 使用FileWriter写入文件
3 */
4 public class Demo02 {
5 public static void main(String[] args) throws Exception{
6 //1.创建FileWriter对象
7 FileWriter fw = new FileWriter("D://javaText2.txt");
8
9 //2.写入
10 for (int i = 0; i < 10; i++) {
11 fw.write("Hello World\r\n"); // \r\n换行
12 fw.flush(); //刷新
13 }
14
15 //3.关闭
16 fw.close();
17 }
18 }

字符流案例-复制

 1 /**
2 * 使用FileReader和FileWrite复制文本文件
3 * 注:不能复制图片或二进制文件,图片使用字节流复制,字节流可以复制任意文件
4 */
5 public class Demo03 {
6 public static void main(String[] args) throws Exception{
7 FileReader fr = new FileReader("D://javaText.txt");
8 FileWriter fw = new FileWriter("D://javaText2.txt");
9 char[] bytes = new char[2];
10 int count;
11 while ((count=fr.read(bytes))!=-1){
12 fw.write(bytes);
13 fw.flush();
14 }
15 fr.close();
16 fw.close();
17 }
18 }

字符缓冲流

  • 缓冲流:BufferedReader/BufferedWriter

    • 高效读写
    • 支持换行输入符
    • 可一次写一行、读一行。
 1 /**
2 * 使用字符缓冲流读取文件
3 * BufferedReader
4 */
5 public class Demo04 {
6 public static void main(String[] args) throws Exception{
7 //1.创建缓冲流节点流FileReader
8 FileReader fr = new FileReader("D://javaText.txt");
9 //2.创建缓冲流
10 BufferedReader br = new BufferedReader(fr);
11
12 //3.读取
13 //第一种方式读取
14 //3.1 单字符读取
15 /*
16 int count;
17 while ((count=br.read())!=-1){
18 System.out.println((char)count);
19 }
20 */
21 //3.2 自设定缓冲区,多个字符读取
22 /*
23 char[] chars = new char[15];
24 int count;
25 while ((count=br.read(chars,0,chars.length))!=-1){
26 System.out.println(new String(chars,0,count));
27 }
28 */
29
30 //第二种方式读取,一行一行读取
31 String line;
32 while ((line=br.readLine())!=null){
33 System.out.println(line);
34 }
35
36 //4.关闭
37 br.close();
38 }
39 }
 1 /**
2 * 使用字符缓冲流写入文件
3 * BufferedWriter
4 */
5 public class Demo05 {
6 public static void main(String[] args) throws Exception{
7 //1.创建节点流
8 FileWriter fw = new FileWriter("D://javaText2.txt");
9 //2.创建缓冲输出流
10 BufferedWriter bw = new BufferedWriter(fw);
11 //3.写入
12 for (int i = 0; i < 10; i++) {
13 bw.write("好好学习,天天向上");
14 bw.newLine();//写入一个换行,windows种\r\n代表换行,Linux种\n代表换行
15 bw.flush();
16 }
17 //4.关闭
18 bw.close();
19 }
20 }
 1 /**
2 * 使用字符缓冲流复制文件
3 * BufferedWriter
4 */
5 public class Demo06 {
6 public static void main(String[] args) throws Exception{
7 //1.创建缓冲输入节点流
8 FileReader fr = new FileReader("D://javaText.txt");
9
10 //2.创建缓冲输入流
11 BufferedReader br = new BufferedReader(fr);
12
13 //3.创建缓冲输出节点流
14 FileWriter fw = new FileWriter("D://javaText3.txt");
15
16 //4.创建缓冲输出流
17 BufferedWriter bw = new BufferedWriter(fw);
18
19 //5.定义String变量用于接收br.readline数据
20 String line;
21
22 //6.读取、写入
23 while ((line=br.readLine())!=null){ //按行读取,读取内容存放在变量line种,直到读到null为止
24 bw.write(line); //缓冲区写入
25 bw.newLine(); //换行
26 bw.flush(); //刷新
27 }
28
29 //7.关闭流
30 bw.close();
31 fw.close();
32 fr.close();
33 br.close();
34 }
35 }

打印流

  • PrintWriter:

    • 封装了print()/println()方法,支持写入后换行。
    • 支持数据原样打印。打印到文件中,常用于日志打印
 1 /**
2 * PrintWriter的使用
3 */
4 public class Demo07 {
5 public static void main(String[] args) throws Exception{
6 PrintWriter pw = new PrintWriter("D://javaText.txt");
7 pw.println(97); //97
8 pw.println('a'); //a
9 pw.println("hello"); //hello
10 pw.println(true); //true
11 pw.close();
12 System.out.println("执行完毕,已打印到指定文本");
13 }
14 }

转换流

  • 桥转换流:InputStreamReader/OutputStreamWriter

    • 可将字节流转换为字符流。
    • 可设置字符的编码方式。
 1 /**
2 * 使用InputStreamReader读取文件
3 */
4 public class Demo08 {
5 public static void main(String[] args) throws Exception{
6 //1.创建转换流的节点流
7 FileInputStream fis = new FileInputStream("D://javaText.txt");
8 //2.创建转换流
9 InputStreamReader isr = new InputStreamReader(fis,"utf-8");//InputStreamReader可以选择字节转换成字符的编码格式
10
11 //3.读取文件
12 //3.1 单个字节转换成字符读取
13 /*
14 int count;
15 while ((count=isr.read())!=-1){
16 System.out.println((char) count);
17 }
18 fis.close();
19 */
20 //3.2 多个字节转换成字符读取
21 char[] chars = new char[5];
22 int count;
23 while ((count=isr.read(chars,0,chars.length))!=-1){
24 System.out.println(new String(chars,0,count));
25 }
26
27 //4.关闭流
28 isr.close();
29 }
30 }
 1 /*
2 *使用OutputStreamWriter写入文件
3 */
4 public class Demo09 {
5 public static void main(String[] args) throws Exception{
6 //1.创建转换输出流的节点流
7 FileOutputStream fos = new FileOutputStream("D://javaText2.txt");
8 //2.创建转换输出流,选择编码格式
9 OutputStreamWriter osw = new OutputStreamWriter(fos,"utf-8");
10 //3.写入
11 for (int i = 0; i < 10; i++) {
12 osw.write("生命之所以有意义是因为它会停止\r\n");
13 osw.flush();
14 }
15 //4.关闭
16 osw.close();
17 fos.close();
18 }
19 }

File类

  • 概念:代表物理盘符中的一个文件或者文件夹。

  • 方法:

    • public boolean CreateNewFile()

      当且仅当指定的文件名不存在时创建一个指定的新的、空的文件。创建成功返回true,如果指定文件名已存在返回false。

    • public boolean mkdir()

      创建一个指定路径名的文件夹。当且仅当文件夹被创建时返回true,否则返回false。

    • public boolean delete()

      删除一个指定的文件或文件夹,文件夹必须为空才能被删除。当且仅当指定的文件或文件夹被删除时返回true,否则返回false。

    • public boolean exists()

      检查指定的文件或文件夹是否存在。当且仅当指定的文件或者文件夹存在时返回true,否则返回false。

    • public File[] listFiles()

      列出目录中的所有内容,返回一个指定路径名中的文件数组,如果指定的路径名不代表一个文件夹(目录)就返回null。

    • public boolean renameTo(File dest)

      重命名一个路径名所指定的文件。当且仅当修改操作成功时返回true,否则返回false。

分隔符

 1 /*
2 *分隔符
3 */
4 public class Demo01 {
5 public static void main(String[] args) {
6 separator();
7 }
8
9 public static void separator(){
10 System.out.println("路径分隔符"+ File.pathSeparator);
11 System.out.println("名称分隔符"+ File.separator);
12 }
13 }

文件操作

 1 /*
2 *文件操作
3 */
4 public class Demo02 {
5 public static void main(String[] args) throws IOException, InterruptedException {
6 fileOp();
7 }
8 public static void fileOp() throws IOException, InterruptedException {
9
10 //1.创建文件
11 //1.1 创建File对象
12 File file = new File("D://File_JavaTest//test01.txt");
13 //1.2 创建文件
14 if (!file.exists()){ //file.exists()判断文件是否存在,存在返回True,因为是要对不存在创建,所以前面加了个!进行取反
15 boolean newFile = file.createNewFile();//创建文件,createNewFile()返回的是boolean类型,所以声明一个变量,打印出来看看是否创建
16 System.out.println(newFile);
17 }
18
19 //2.删除文件
20 //2.1 直接删除
21 /*System.out.println("删除结果"+file.delete());*/
22 //2.2 使用JVM退出时删除(不是自己删除)
23 file.deleteOnExit();
24 Thread.sleep(5000);//调用休眠程序观察删除操作
25
26 //3.获取文件信息
27 System.out.println("文件绝对路径:"+file.getAbsolutePath());
28 System.out.println("获取路径:"+file.getParent());
29 System.out.println("获取父目录:"+file.getParent());
30 System.out.println("获取文件名称:"+file.getName());
31 System.out.println("获取文件长度:"+file.length());
32 System.out.println("获取文件创建时间:"+new Date(file.lastModified()).toLocaleString());
33
34 //4.判断
35 System.out.println("是否可写:"+file.canWrite());
36 System.out.println("是否可读:"+file.canRead());
37 System.out.println("是否隐藏:"+file.isHidden());
38 System.out.println("是否是文件:"+file.isFile());
39 System.out.println("是否是文件夹:"+file.isDirectory());
40 }
41 }

文件夹操作

 1 /*
2 *文件夹操作
3 */
4 public class Demo03 {
5 public static void main(String[] args) {
6 directorOp();
7 }
8 public static void directorOp(){
9 //1.创建文件夹
10 File file = new File("D://aaaaa//bbbbb//ccccc");
11 if (!file.exists()){
12 //单级目录创建mkdir
13 /*boolean mkdir = file.mkdir(); mkdir只能创建单级目录*/
14 //多级目录创建mkdirs
15 boolean mkdirs = file.mkdirs();
16 System.out.println(mkdirs);
17 }
18
19 //2.删除文件夹
20 //2.1 直接删除(必须为空目录),只删除最后一个目录即ccccc
21 /*System.out.println("删除结果:"+file.delete());*/
22 //2.2 使用jvm删除
23 file.deleteOnExit();
24
25 //3.获取文件夹信息
26 System.out.println("获取绝对路径:"+file.getAbsolutePath());
27 System.out.println("获取路径:"+file.getPath());
28 System.out.println("获取父目录:"+file.getParent());
29 System.out.println("获取创建时间:"+new Date(file.lastModified()).toString());
30 System.out.println("文件夹名称:"+file.getName());
31
32 //4.判断
33 System.out.println("是否隐藏:"+file.isHidden());
34 System.out.println("是否是文件:"+file.isFile());
35
36 //5.遍历文件夹
37 File file1 = new File("D://");
38 String[] list = file1.list();
39 for (String string:list) {
40 System.out.println(string);
41 }
42 }
43 }

文件过滤器

  • FileFilter接口:

    public interface FileFilter

    • boolean accepte(File pathname)
    • 当调用File类中的listFiles()方法时,支持传入FileFilter接口实现类,对获取的文件进行过滤,只有满足条件的文件才可以出现在listFiles()的返回值中。
public class Demo04 {
public static void main(String[] args) {
filerFitter();
} public static void filerFitter() {
File file = new File("D:\\aaaaa"); File[] files = file.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
if (pathname.getName().endsWith(".jpg")){
return true;
}
return false;
}
}); for (File f:files) {
System.out.println(f.getName());
}
}
}

文件操作案例-递归遍历文件夹和递归删除文件夹文件

 1 /*
2 *递归遍历文件夹
3 */
4 public class Demo05 {
5 public static void main(String[] args) {
6 listDir(new File("D://aaaaa")); //调用listDir方法,new一个file对象入参
7 }
8 public static void listDir(File dir){ //此时的dir已经是实例化的File对象
9 File[] files = dir.listFiles(); //调用File类里面的listFiles方法,得到的是一个File类型的数组,返回的是该目录中的文件和目录
10 System.out.println(dir.getAbsolutePath()); //打印dir的绝对路径
11 if(files!=null&&files.length>0){ //判断返回的内容有没有数据
12 for (File f:files) { //遍历返回的数组内容
13 if(f.isDirectory()){ //判断是否是文件夹
14 listDir(f); //递归自己,调用自己,对文件夹重新走一遍listDir方法
15 }
16 else{
17 System.out.println(f.getAbsolutePath());//打印绝对路径
18 }
19 }
20 }
21 }
22 }
 1 /*
2 *递归删除文件夹
3 */
4 public class Demo06 {
5 public static void main(String[] args) {
6 deleteDir(new File("D://aaaaa"));
7 }
8 public static void deleteDir(File dir){
9 File[] files = dir.listFiles();
10 System.out.println(dir.getAbsolutePath());
11 if(files!=null&&files.length>0){
12 for (File f:files) {
13 if(f.isDirectory()){
14 deleteDir(f);
15 }
16 else {
17 f.delete();
18 }
19 }
20 }
21 }
22 }

补充:Properties

  • Properties:属性集合

  • 特点:

  • 存储属性名和属性值(键值对)。

    • 属性名和属性值都是字符串类型。
    • 没有泛型。
    • 和流有关(所以没有整理在集合里面)。
  • 方法:

    • public String getProperty(String key)

      根据key在属性列表里查找value,如果原始属性列表找不到就去默认属性列表找。返回key所对应的value。

    • public void list(PrintWriter out)

      将属性列表打印在指定的输出流上,在debug时很有用。

    • public Object setProperty(String key,String value)

      内部调用的是Hashtable的put方法,将key和value成对地保存在属性列表中。返回这个key上一个对应的value,没有就返回null。

    Properties可以保存在一个流中或是从一个流中加载,属性列表中的每个键值对都是一个字符串。一个属性列表可以包括另一个第二属性列表来作为它的默认值,如果在原始属性列表中没有找到key时就搜索第二属性列表。

 1 /**
2 * 演示集合properties的使用
3 */
4 public class Demo01 {
5 public static void main(String[] args) throws IOException {
6 //1.创建集合
7 Properties properties = new Properties();
8 //2.添加数据
9 properties.setProperty("username","张三");
10 properties.setProperty("age","22");
11 System.out.println(properties.toString());
12 //3.遍历
13 //遍历
14 //3.1 keySet 略
15 //3.2 entrySet 略
16 //3.3 stringPropertyNames()
17 Set<String> set=properties.stringPropertyNames();
18 for (String string : set) {
19 System.out.println(string+" "+properties.getProperty(string));
20 }
21
22 //和流有关的方法
23 //list
24 PrintWriter printWriter=new PrintWriter("d:\\print.txt");
25 properties.list(printWriter);
26 printWriter.close();
27 //store保存
28 FileOutputStream fileOutputStream=new FileOutputStream("d:\\s.properties");
29 properties.store(fileOutputStream, "NOTES");
30 fileOutputStream.close();
31 //load加载
32 Properties properties2=new Properties();
33 FileInputStream fileInputStream=new FileInputStream("d:\\s.properties");
34 properties2.load(fileInputStream);
35 fileInputStream.close();
36 System.out.println(properties2.toString());
37 }
38 }

Java I/O框架 - 总结概述的更多相关文章

  1. 构建自己的Java并发模型框架

    Java的多线程特性为构建高性能的应用提供了极大的方便,可是也带来了不少的麻烦.线程间同步.数据一致性等烦琐的问题须要细心的考虑,一不小心就会出现一些微妙的,难以调试的错误. 另外.应用逻辑和线程逻辑 ...

  2. Java常用日志框架介绍

    Java常用日志框架介绍 java日志概述 对于一个应用程序来说日志记录是必不可少的一部分.线上问题追踪,基于日志的业务逻辑统计分析等都离不日志.java领域存在多种日志框架,目前常用的日志框架包括L ...

  3. 构建Java并发模型框架

    Java的多线程特性为构建高性能的应用提供了极大的方便,但是也带来了不少的麻烦.线程间同步.数据一致性等烦琐的问题需要细心的考虑,一不小心就会出现一些微妙的,难以调试的错误.另外,应用逻辑和线程逻辑纠 ...

  4. spring框架的概述与入门

    1. Spring框架的概述 * Spring是一个开源框架 * Spring是于2003 年兴起的一个轻量级的Java开发框架,由Rod Johnson在其著作Expert One-On-One J ...

  5. Java常用日志框架介绍(转)

    Java常用日志框架介绍 java日志概述 对于一个应用程序来说日志记录是必不可少的一部分.线上问题追踪,基于日志的业务逻辑统计分析等都离不日志.java领域存在多种日志框架,目前常用的日志框架包括L ...

  6. Java并发模型框架

    构建Java并发模型框架 Java的多线程特性为构建高性能的应用提供了极大的方便,但是也带来了不少的麻烦.线程间同步.数据一致性等烦琐的问题需要细心的考虑,一不小心就会出现一些微妙的,难以调试的错误. ...

  7. Spring 框架的概述以及Spring中基于XML的IOC配置

    Spring 框架的概述以及Spring中基于XML的IOC配置 一.简介 Spring的两大核心:IOC(DI)与AOP,IOC是反转控制,DI依赖注入 特点:轻量级.依赖注入.面向切面编程.容器. ...

  8. Java注解【一、概述】

    前面几篇Java学习笔记都是半夜写的,比较伤身体,今天开始想调整生物钟,早上起来学2小时,看看能坚持多久 本周目标: 1.JavaJDBC使用 2.JavaWeb编程 3.Java框架基础(反射+注解 ...

  9. Java 高级-集合框架

    参考资料 参考 HashMap 类似 C++ 中的 STL 标准模板库,Java 也在 java.util 包中封装了一套常用数据结构及其算法,称为集合框架.所有的集合框架都包含如下内容: 接口:代表 ...

随机推荐

  1. golang中的闭包_closure

    闭包_Closure: 1.一般情况下,第一类对象都是独立的封闭的存在的,独立的封闭的起作用; 2.第一类对象可以被创建; 3.第一类对象可以作为参数传递给其他函数; 4.第一类对象可以赋值给变量实体 ...

  2. docker-compose 的使用和负载均衡的初探

    docker-compose 的使用和负载均衡的初探 前言 a. 本文主要为 Docker的视频教程 笔记. b. 环境为 CentOS 7.0 云服务器 c. 上一篇:Docker 私有仓库 1. ...

  3. 使用SQL SERVER存储过程实现历史数据迁移

    今天讲下软件开发中最常见的历史数据迁移方式.在讲迁移之前,先简单介绍下几个基本概念. 1.什么是历史数据迁移? 简单直白地说:就是将一些创建时间比较久而且不常用的历史数据,存储到另一个地方(可以是另一 ...

  4. Django学习day04随堂笔记

    每日测验 """ 今日考题 1.列举你知道的orm数据的增删改查方法 2.表关系如何判定,django orm中如何建立表关系,有什么特点和注意事项 3.请画出完整的dj ...

  5. video.js视频播放插件

    1 初始化 Video.js初始化有两种方式. 1.1 标签方式 一种是在<video>标签里面加上class="video-js"和data-setup='{}'属性 ...

  6. 用 shell 脚本做命令行工具扩展

    问题的提出 公司开发机与远程服务器之间有严格的隔离策略,不能直接使用 ssh 登录,而必需通过跳板机.这样一来,本地与服务器之间的一些文件传输变得非常不便.经过咨询,运维教了我一招: $ nc -l ...

  7. Java基础系列(11)- 变量、常量、作用域以及变量的命名规范

    变量 变量是什么:就是可以变化的量 Java是一种强类型语言,每个变量都必须声明其类型 Java变量是程序中最基本的存储单元,其要素包括变量名,变量类型和作用域 type varName [=valu ...

  8. 常用的word技巧

    自动生成标题 自动生成目录 显示导航列 修订 查看最终版本

  9. php 扫描url死链接

    * 从Packagist上搜索需要的包 https://packagist.org/ * 通过composer下载依赖包 composer require guzzlehttp/guzzle comp ...

  10. 实验4:开源控制器实践——OpenDaylight

    实验4:开源控制器实践--OpenDaylight 一.实验目的 能够独立完成OpenDaylight控制器的安装配置: 能够使用Postman工具调用OpenDaylight API接口下发流表. ...