好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

Java中的IO流总结(推荐)

I/O简介

I/O是Input/output的缩写,在java中,对于数据的输入和输出以流的方式进行。java.io包下提供了各种[流]类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据。 

输入输出都是基于内存的角度来说的 。输入:读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中。 输出:输出output:将程序(内存)数据输出到磁盘、光盘等存储设备中。

流的分类

按 操作数据单位 不同分为:字节流(8 bit),字符流(16 bit)

按 数据流的流向 不同分为:输入流,输出流

按 流的角色 的不同分为:节点流,处理流  

节点流:直接从数据源或目的地读写数据。  

处理流:不直接连接到数据源或目的地,而是[连接]在已存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写功能。 相当于是二次包装。

抽象基类 字节流 字符流
输入流 InputStream Reader
输出流 OutputStream Writer

Java的IO流共涉及40多个类,实际上非常规则,都是从这4个抽象基类派生的。 由这四个类派生出来的子类名称都是以其父类名作为子类名后缀。

字节流和字符流常用API

InputStream

int read():从输入流中读取数据的下一个字节。返回0到255范围内的int字节值。如果读到流的末尾,则返回 -1。 此 方法一次只读一个字节,效率太低,一般不用 int read(byte[] b):从此输入流中将最多b.length个字节的数据保存到一个byte数组中。返回实际读取字节长度,如果读到流的末尾,也返回 -1。 int read(byte[] b,int off,int len):将输入流中最多len个数据字节读入byte数组。尝 试读取len个字节,但读取的字节也可能小于该值,实际读取个数以读取到的为准 ,比如长度为23个字节的内容,每次读取5个字节,则第五次读取流并没处于末尾,还剩长度是3,故返回3。第六次读取发现是末尾,则返回 -1 。一般都用此方法。 public void close() throws IOException:关闭此输入流并释放与该流关联的所有系统资源, 一定要关闭。

Reader

Reader和InputStream类似,就是将字节数组换成了字符数组 int read(); 效果与字节流一致 int read(char[] cbuf); 效果与字节流一致 int read(char[] cbuf,int off,int len); 效果与字节流一致 public void close() throws IOException;关闭此输入流并释放与该流关联的所有系统资源, 字符流的必须要关闭,不然会出问题

OutputStream

void write(int b) :将指定的字节写入此输出流。 void write( byte[] b) :将b.length个字节从指定的byte数组写入此输出流。 void write(byte[] b,int off,int len):将指定byte数组中从偏移量off开始的len个字节写入此输出流。 public void flush() throws IOException:刷新此输出流并强制写出所有缓冲的输出字节,调用此方法指示应将这些字节立即写入它们预期的目标。就是将缓冲的字节全部写出到字节或字符数组中。 public void close() throws IOException:关闭此输入流并释放与该流关联的所有系统资源

Writer

void write(int c):写入单个字符。 void write(char[] cbuf):写入字符数组。 void write(char[] cbuf,int off,int len) : 写入字符数组的某一部分。从off开始,写入len个字符 void write(String str):写入字符串。 void write(String str,int off,int len):写入字符串的某一部分。 void flush():刷新该流的缓冲,则立即将它们写入预期目标。 public void close() throws IOException:关闭此输入流并释放与该流关联的所有系统资源

字节字符流相关操作

字节流读取文本内容

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

// 读取文本文件内容,用字节流去读,可能会乱码

     public void test1() {

         InputStream inputStream = null ;

         try {

             inputStream = new FileInputStream( "hello.txt" ); //相对路径是工程路径下

             int len;

             byte [] bytes = new byte [ 5 ]; // 定义5字节长度的byte数组

             while ((len = inputStream.read(bytes)) != - 1 ) { // 将数据读到byte数组中

                 System.out.println( new String(bytes, 0 , len)); //打印到控制台

             }

         } catch (Exception e) {

             e.printStackTrace();

         } finally {

             try {

                 if (inputStream != null ) {

                     inputStream.close();

                 }

             } catch (IOException e) {

                 e.printStackTrace();

             }

         }

     }

字符流读取文本内容

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

// 读取文本文件内容,用字符流去读,不会乱码,最多重复   

     public void test2() {

         Reader reader = null ;

         try {

             reader = new FileReader( "hello.txt" );

             int len;

             char [] charBuff = new char [ 5 ];

             while ((len = reader.read(charBuff)) != - 1 ) {

//                System.out.println(new String(charBuff)); // 注意这两行的代码区别

                 System.out.println( new String(charBuff, 0 , len));

             }

         } catch (Exception e) {

             e.printStackTrace();

         } finally {

             try {

                 if (reader != null ) {

                     reader.close();

                 }

             } catch (IOException e) {

                 e.printStackTrace();

             }

         }

     }

字节流读取文件到输出到指定位置

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

public void test3() {

         InputStream inputStream = null ;

         OutputStream outputStream = null ;

         try {

             inputStream = new FileInputStream( "hello.txt" ); // 读取文件

             outputStream = new FileOutputStream( "hello2.txt" ); // 相对路径,默认是工程路径下

             int len;

             byte [] bytes = new byte [ 5 ];

             while ((len = inputStream.read(bytes)) != - 1 ) {

                 outputStream.write(bytes, 0 , len);

             }

         } catch (Exception e) {

             e.printStackTrace();

         } finally {

             try {

                 if (inputStream != null ) {

                     inputStream.close();

                 }

                 if (outputStream != null ){

                     outputStream.close();

                 }

             } catch (IOException e) {

                 e.printStackTrace();

             }

         }

     }

字符流读取文件到输出到指定位置

字符流读取文件到输出到指定位置时, 如果没有手动关闭流,则不会输出到指定位置,需要手动flush。但是如果在finally块中关闭了流,则会自动flush。 在close()操作中,会帮我们flush。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

public void test4() {

         Reader reader = null ;

         Writer writer = null ;

         try {

             reader = new FileReader( "hello2.txt" );

             writer = new FileWriter( "hello3.txt" );

             int len;

             char [] charBuff = new char [ 5 ];

             while ((len = reader.read(charBuff)) != - 1 ) {

                 writer.write(charBuff, 0 , len);

//                writer.flush();

             }

         } catch (Exception e) {

             e.printStackTrace();

         } finally {

             try {

                 if (reader != null ) {

                     reader.close();

                 }

                 if (writer != null ) { // 一定要关闭字符流,否则要手动flush

                     writer.close();

                 }

             } catch (IOException e) {

                 e.printStackTrace();

             }

         }

     }

注意, 字符流用来处理字符串很便捷,并且只能操作普通的文本文件 ,例如:.txt,.java,.c,.cpp 等语言的源代码。尤其注意.doc,excel,ppt这些不是文本文件。 字节流既可以操做文本文件,也可以操作字节文件 ,比如.mp3,.avi,.rmvb,mp4,.jpg,.doc,.ppt。 如果用字符流来操作图片等字节文件,生成的文件是无法打开的!

缓冲流

为了提高数据读写的速度,Java API提供了带缓冲功能的流类,在使用这些流类时,会创建一个内部缓冲区数组,缺省使用 8192个字节(8Kb) 的缓冲区。

缓冲流要[套接]在相应的节点流之上,根据数据操作单位可以把缓冲流分为 BufferedInputStream和ufferedOutputStream 以及 BufferedReader和BufferedWriter 。分别对应字节缓冲流和字符缓冲流。相当于在字节和字符流上包装了一下。

BufferedInputStream和BufferedOutputStream

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

public void test() {

         InputStream inputStream ;

         OutputStream outputStream ;

         BufferedInputStream bis = null ;

         BufferedOutputStream bos = null ;

         try {

             inputStream = new FileInputStream( "modify.txt" ); //小于8KB

             outputStream = new FileOutputStream( "modify2.txt" );

             bis = new BufferedInputStream(inputStream);

             bos = new BufferedOutputStream(outputStream);

             int len;

             byte [] bytes = new byte [ 5 ];

             while ((len = bis.read(bytes)) != - 1 ) {

                 bos.write(bytes, 0 , len);

             }

         } catch (Exception e) {

             e.printStackTrace();

         } finally {

             try {

                 if (bis != null ) {

                     bis.close();

                 }

                 if (bos != null ){

                     bos.close();

                 }

             } catch (IOException e) {

                 e.printStackTrace();

             }

         }

     }

BufferedReader和BufferedWriter

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

public void test2() {

         Reader reader ;

         Writer writer ;

         BufferedReader br = null ;

         BufferedWriter bw = null ;

         try {

             reader = new FileReader( "modify.txt" );

             writer = new FileWriter( "modify2.txt" );

             br = new BufferedReader(reader);

             bw = new BufferedWriter(writer);

             int len;

             char [] bytes = new char [ 5 ];

             while ((len = br.read(bytes)) != - 1 ) {

                 bw.write(bytes, 0 , len);

             }

         } catch (Exception e) {

             e.printStackTrace();

         } finally {

             try {

                 if (br != null ) {

                     br.close();

                 }

                 if (bw != null ){

                     bw.close();

                 }

             } catch (IOException e) {

                 e.printStackTrace();

             }

         }

     }

**缓冲流如果没有手动关闭流,且读取的文件小于底层缓存大小8KB,是不会自动写到目标中去的,需要手动flush。**在关闭流时,只需关闭缓冲流即可,它会自动关闭它包装的底层节点流。

数据流

为了方便地操作Java语言的基本数据类型和String的数据,可以使用数据流。数据流有两个类: DataInputStream和DataOutputStream , 别[套接]在InputStream和OutputStream子类的流上。

使用如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

public void test() {

        DataOutputStream dos = null ;

        try {

            OutputStream outputStream = new FileOutputStream( "data.txt" );

            dos = new DataOutputStream(outputStream);

            dos.writeUTF( "热烈庆祝中国共产党成立一百周年" );

            dos.writeInt( 100 );

            dos.writeBoolean( true );

            System.out.println( "成功!" );

        } catch (IOException e) {

            e.printStackTrace();

        } finally {

            try {

                if (dos != null ) {

                    dos.close();

                }

            } catch (IOException e) {

                e.printStackTrace();

            }

        }

    }

    public void test2(){

        DataInputStream dis =  null ;

        try {

            InputStream inputStream = new FileInputStream( "data.txt" );

            dis = new DataInputStream(inputStream);

            System.out.println(dis.readUTF()); //读取时要按照写入顺序读取

            System.out.println(dis.readInt());

            System.out.println(dis.readBoolean());

            System.out.println( "成功!" );

        } catch (IOException e) {

            e.printStackTrace();

        } finally {

            try {

                if (dis != null ) {

                    dis.close();

                }

            } catch (IOException e) {

                e.printStackTrace();

            }

        }

    }

对象流

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

序列化:用ObjectOutputStream类保存基本类型数据或对象的机制 反序列化:用ObjectInputStream类读取基本类型数据或对象的机制 ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量

序列化与反序列化的演示

先定义一个Person类,该类必须实现Serializable接口,否则序列化时会报 java.io.NotSerializableException 的错误

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

package day07;

import java.io.Serializable;

import java.util.Date;

public class Person implements Serializable {

     private static final long serialVersionUID = -5858950242987134591L;

     private String name;

     private Integer age;

     private Date date;

     public Person(){}

     public Person(String name, Integer age, Date date) {

         this .name = name;

         this .age = age;

         this .date = date;

     }

   // getter、setter略

     @Override

     public String toString() {

         return "Person{" +

                 "name='" + name + '\ '' +

                 ", age=" + age +

                 ", date=" + date +

                 '}' ;

     }

}

序列化

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

public void test() {

     ObjectOutputStream oos = null ;

     try {

         OutputStream outputStream = new FileOutputStream( "person.txt" ); // 创建输出流对象,指定输出位置

         oos = new ObjectOutputStream(outputStream); // 包装输出流

         oos.writeObject( new Person( "张三" , 22 , new Date())); // 序列化对象

         System.out.println( "序列化成功!" );

     } catch (Exception e) {

         e.printStackTrace();

     } finally {

         if (oos!= null ){

             try {

                 oos.close();

             } catch (IOException e) {

                 e.printStackTrace();

             }

         }

     }

}

反序列化

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

public void test2() {

         ObjectInputStream ois = null ;

         try {

             InputStream inputStream = new FileInputStream( "person.txt" );

             ois = new ObjectInputStream(inputStream);

             Person person = (Person) ois.readObject();

             System.out.println( "person姓名为:" + person.getName());

             System.out.println( "person年龄为:" + person.getAge());

             SimpleDateFormat sdf = new SimpleDateFormat( "yyyy年MM月dd日 hh时mm分ss秒" );

             System.out.println( "创建时间为:" + sdf.format(person.getDate()));

         } catch (IOException e) {

             e.printStackTrace();

         } catch (ClassNotFoundException e) {

             e.printStackTrace();

         } finally {

             if (ois != null ) {

                 try {

                     ois.close();

                 } catch (IOException e) {

                     e.printStackTrace();

                 }

             }

         }

     }

无论如何反序列化,时间都是不变的。

总结

本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注的更多内容!

原文链接:https://blog.csdn.net/weixin_44061521/article/details/118653939

查看更多关于Java中的IO流总结(推荐)的详细内容...

  阅读:13次