Java中的IO框架流三,种类化流

2019-05-12 08:01 来源:未知

十、流

1      IO(三)No20

1.字节流

10.1 缓冲流

1.1    Properties 属性集

1.1.字节输出流output

        10.1.1 概述

                缓冲流是对4个基本的FileXxx流的增强,所以也是4个流,按照数据类型进行分类

                        字节缓冲流:BufferedInputStream,BufferedOutputStream

                        字符缓冲流:BufferedReader,BufferedWriter

                     缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。 

1.1.1.数据写入文件中

         10.1.2 字节缓冲流 构造方法:

                    构造方法

 

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

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

Properties属性集,主要用于操作配置属性,

通过api查找 output 。找到很多,其中 java.io.OutputStream ,OutputStream: 输出字节流的超类。

         10.1.3 字符缓冲流

                构造方法

 

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

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

                特有方法:

                字符缓冲流的基本方法与普通字符流调用方式一致,不再阐述, 我们来看它们具备的特有方法。

 

  • BufferedReader:public String readLine(): 读一行文字。 

  • BufferedWriter:public void newLine(): 写一行行分隔符,由系统属性定义符号。

是以键值对的方式来保存属性,并且都是String类型

小编整理了一些java进阶学习资料和面试题,需要资料的请加JAVA高阶学习Q群:664389243 这是小编创建的java高阶学习交流群,加群一起交流学习深造。群里也有小编整理的2019年最新最全的java高阶学习资料!

10.2 转换流

继承自Hashtable类,所以是一个Map集合,具有Map接口中的所有方法,但是在保存和读取数据的时候不建议使用put和get方法,因为有可能会出现异常,建议使用Properties中特有的方法进行数据的存储

基本特点:

        10.2.1 字符编码和字符集

                

字符编码

计算机中储存的信息都是用二进制数表示的,而我们在屏幕上看到的数字、英文、标点符号、汉字等字符是二进制数转换之后的结果。按照某种规则,将字符存储到计算机中,称为编码 。反之,将存储在计算机中的二进制数按照某种规则解析显示出来,称为解码 。比如说,按照A规则存储,同样按照A规则解析,那么就能显示正确的文本f符号。反之,按照A规则存储,再按照B规则解析,就会导致乱码现象。

字符编码Character Encoding : 就是一套自然语言的字符与二进制数之间的对应规则。

字符集

字符集 Charset:是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等。

计算机要准确的存储和识别各种字符集符号,需要进行字符编码,一套字符集必然至少有一套字符编码。常见字符集有ASCII字符集、GBK字符集、Unicode字符集等。 data-src="img/1_charset.jpg">韦德娱乐1946网页版 1

可见,当指定了编码,它所对应的字符集自然就指定了,所以编码才是我们最终要关心的。

ASCII字符集
ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统,用于显示现代英语,主要包括控制字符(回车键、退格、换行键等)和可显示字符(英文大小写字符、阿拉伯数字和西文符号)。
基本的ASCII字符集,使用7位(bits)表示一个字符,共128字符。ASCII的扩展字符集使用8位(bits)表示一个字符,共256字符,方便支持欧洲常用字符。
ISO-8859-1字符集
拉丁码表,别名Latin-1,用于显示欧洲使用的语言,包括荷兰、丹麦、德语、意大利语、西班牙语等。
ISO-5559-1使用单字节编码,兼容ASCII编码。
GBxxx字符集
GB就是国标的意思,是为了显示中文而设计的一套字符集。
GB2312:简体中文码表。一个小于127的字符的意义与原来相同。但两个大于127的字符连在一起时,就表示一个汉字,这样大约可以组合了包含7000多个简体汉字,此外数学符号、罗马希腊的字母、日文的假名们都编进去了,连在ASCII里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的"全角"字符,而原来在127号以下的那些就叫"半角"字符了。
GBK:最常用的中文码表。是在GB2312标准基础上的扩展规范,使用了双字节编码方案,共收录了21003个汉字,完全兼容GB2312标准,同时支持繁体汉字以及日韩汉字等。
GB18030:最新的中文码表。收录汉字70244个,采用多字节编码,每个字可以由1个、2个或4个字节组成。支持中国国内少数民族的文字,同时支持繁体汉字以及日韩汉字等。
Unicode字符集
Unicode编码系统为表达任意语言的任意字符而设计,是业界的一种标准,也称为统一码、标准万国码。
它最多使用4个字节的数字来表达每个字母、符号,或者文字。有三种编码方案,UTF-8、UTF-16和UTF-32。最为常用的UTF-8编码。
UTF-8编码,可以用来表示Unicode标准中任何字符,它是电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。所以,我们开发Web应用,也要使用UTF-8编码。它使用一至四个字节为每个字符编码,编码规则:
128个US-ASCII字符,只需一个字节编码。
拉丁文等字符,需要二个字节编码。
大部分常用字(含中文),使用三个字节编码。
其他极少使用的Unicode辅助字符,使用四字节编码。

 

常用方法:

1、操作的数据都是字节。

        10.2.2 出现的问题

                在IDEA中,使用FileReader 读取项目中的文本文件。由于IDEA的设置,都是默认的UTF-8编码,所以没有任何问题。但是,当读取Windows系统中创建的文本文件时,由于Windows系统的默认是GBK编码,就会出现乱码。

public class ReaderDemo { public static void main(String[] args) throws IOException { FileReader fileReader = new FileReader("E:\File_GBK.txt"); int read; while ((read = fileReader.read()) != -1) { System.out.print((char)read); } fileReader.close(); } } 输出结果: ���

 

 

 

12

 

 

 

 

 

1

public class ReaderDemo {

2

    public static void main(String[] args) throws IOException {

3

        FileReader fileReader = new FileReader("E:\File_GBK.txt");

4

        int read;

5

        while ((read = fileReader.read()) != -1) {

6

            System.out.print((char)read);

7

        }

8

        fileReader.close();

9

    }

10

}

11

输出结果:

12

���

 

 

1、添加、获取

2、定义了输出字节流的基本共性功能。

         10.2.3 InputStreamReader类

转换流java.io.InputStreamReader,是Reader的子类,是从字节流到字符流的桥梁。它读取字节,并使用指定的字符集将其解码为字符。它的字符集可以由名称指定,也可以接受平台的默认字符集。

GBK : 一个汉字对应2个字节

Utf-8 : 一个汉字对应3个字节

构造方法

InputStreamReader(InputStream in) > data-wiz-span="data-wiz-span">: 创建一个使用默认字符集的字符流。

InputStreamReader(InputStream in, String charsetName) > data-wiz-span="data-wiz-span">: 创建一个指定字符集的字符流。

 

setProperty(String key,String value):添加键值对

3、输出流中定义都是写write方法。操作字节数组write,操作单个字节 write 。

           10.2.4 OutputStreamWriter 类

转换流java.io.OutputStreamWriter ,是Writer的子类,是从字符流到字节流的桥梁。使用指定的字符集讲字符编码为字节。它的字符集可以由名称指定,也可以接受平台的默认字符集。

构造方法

OutputStreamWriter(OutputStream in) > data-wiz-span="data-wiz-span">: 创建一个使用默认字符集的字符流。

OutputStreamWriter(OutputStream in, String charsetName) > data-wiz-span="data-wiz-span">: 创建一个指定字符集的字符流。

    

                   

getProperty(String key):通过键获取值《getProperty(Stringkey)

子类有规律:所有的子类名称后缀是父类名,前缀名是这个流对象功能。

                转换流理解图解

韦德娱乐1946网页版 2

 

getProperty(Stringkey,StringdefaultValue)》如果键不存在返回默认值

想要操作文件: FileOutputStream

10.3 序列化流

2、保存、加载(配合IO流使用)

1publicclassFileOutputStreamDemo {2publicstaticvoidmain(String[] args)throwsIOException {3//需求:将数据写入到文件中。4//创建存储数据的文件。5Filefile=newFile("c:\file.txt");6//创建一个用于操作文件的字节输出流对象。一创建就必须明确数据存储目的地。7//输出流目的是文件,会自动创建。如果文件存在,则覆盖。8FileOutputStream fos =newFileOutputStream;9//调用父类中的write方法。10byte[] data ="abcde".getBytes();11fos.write;12//关闭流资源。13fos.close();14}15}

        10.3.1 概述

Java 提供了一种对象序列化的机制。用一个字节序列可以表示一个对象,该字节序列包含该对象的数据对象的类型对象中存储的数据等信息。字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息。

反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化对象的数据对象的类型和`对象中存储的数据`信息,都可以用来在内存中创建对象。看图理解序列化:

data-src="img/3_xuliehua.jpg">韦德娱乐1946网页版 3

store():将数据通过输出流写到指定文件中

1.1.2.给文件中续写和换行

10.3.2 ObjectOutputStream类和ObjectInputStream类         构造方法

  •  

    public ObjectOutputStream(OutputStream out) data-wiz-span="data-wiz-span">: 创建一个指定OutputStream的ObjectOutputStream。

     

  • public ObjectInputStream(InputStream in) data-wiz-span="data-wiz-span">:

    创建一个指定InputStream的ObjectInputStream。

            Notes:

                

韦德娱乐1946网页版,1.一个对象要想序列化,必须满足两个条件:

该类必须实现java.io.Serializable 接口,Serializable 是一个标记接口,不实现此接口的类将不会使任何状态序列化或反序列化,会抛出NotSerializableException

2.该类的所有属性必须是可序列化的。如果有一个属性不需要可序列化的,则该属性必须注明是瞬态的,使用transient 关键字修饰。

public class Employee implements java.io.Serializable { public String name; public String address; public transient int age; // transient瞬态修饰成员,不会被序列化 public void addressCheck() { System.out.println("Address check : " name " -- " address); } }

 

 

 

8

 

 

 

 

 

1

public class Employee implements java.io.Serializable {

2

    public String name;

3

    public String address;

4

    public transient int age; // transient瞬态修饰成员,不会被序列化

5

    public void addressCheck() {

6

      System.out.println("Address  check : "   name   " -- "   address);

7

    }

8

}

 

 

 

                    写出对象方法:

> > data-wiz-span="data-wiz-span">public final void writeObject (Object obj) > > data-wiz-span="data-wiz-span">` > > data-wiz-span="data-wiz-span"> : 将指定的对象写出。

public final Object readObject () > > data-wiz-span="data-wiz-span">` > > data-wiz-span="data-wiz-span"> : 读取一个对象。

 

public static void main(String[] args) throws IOException, ClassNotFoundException { Student s1 = new Student(); s1.setName("zhangsan"); s1.setAge(14); s1.setDefault1(9999); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("Student")); oos.writeObject(s1); oos.close(); System.out.println("已经被序列化"); // 反序列化 FileInputStream fis = new FileInputStream("Student.txt"); ObjectInputStream ois = new ObjectInputStream(fis); // 读取一个对象 Student stu = (Student) ois.readObject(); ois.close(); fis.close(); System.out.println("stu = "

  • stu.getName()); System.out.println("stu = " stu.getAge()); System.out.println("stu = " stu.getDefault1()); } // 先序列化 再反序列化

 

 

 

27

 

 

 

 

 

1

    public static void main(String[] args) throws IOException, ClassNotFoundException {

2

        Student s1 = new Student();

3

        s1.setName("zhangsan");

4

        s1.setAge(14);

5

        s1.setDefault1(9999);

6

7

        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("Student"));

8

9

        oos.writeObject(s1);

10

11

        oos.close();

12

        System.out.println("已经被序列化");

13

14

        // 反序列化

15

        FileInputStream fis = new FileInputStream("Student.txt");

16

        ObjectInputStream ois = new ObjectInputStream(fis);

17

        // 读取一个对象

18

        Student stu  = (Student) ois.readObject();

19

        ois.close();

20

        fis.close();

21

22

        System.out.println("stu = "   stu.getName());

23

        System.out.println("stu = "   stu.getAge());

24

        System.out.println("stu = "   stu.getDefault1());

25

    }

26

27

// 先序列化 再反序列化

 

 

        反序列化的时候注意:

    

对于JVM可以反序列化对象,它必须是能够找到class文件的类。如果找不到该类的class文件,则抛出一个 ClassNotFoundException 异常。

反序列化操作2

另外,当JVM反序列化对象时,能找到class文件,但是class文件在序列化对象之后发生了修改,那么反序列化操作也会失败,抛出一个InvalidClassException异常。发生这个异常的原因如下:

该类的序列版本号与从流中读取的类描述符的版本号不匹配
该类包含未知数据类型
该类没有可访问的无参数构造方法

Serializable 接口给需要序列化的类,提供了一个序列版本号。serialVersionUID 该版本号的目的在于验证序列化的对象和对应类是否版本匹配。

public class Student implements Serializable { private String name; private int age; private transient int default1; public Student() { } public Student(String name, int age, int default1) { this.name = name; this.age = age; this.default1 = default1; } public void addressCheck() { System.out.println("Address check :" name "---" age); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public int getDefault1() { return default1; } public void setDefault1(int default1) { this.default1 = default1; } }

 

 

 

42

 

 

 

 

 

1

public class Student implements Serializable {

2

    private String name;

3

    private int age;

4

    private transient int default1;

5

6

    public Student() {

7

    }

8

9

    public Student(String name, int age, int default1) {

10

        this.name = name;

11

        this.age = age;

12

        this.default1 = default1;

13

    }

14

15

    public void addressCheck() {

16

        System.out.println("Address check :"   name   "---"   age);

17

    }

18

19

    public String getName() {

20

        return name;

21

    }

22

23

    public void setName(String name) {

24

        this.name = name;

25

    }

26

27

    public int getAge() {

28

        return age;

29

    }

30

31

    public void setAge(int age) {

32

        this.age = age;

33

    }

34

35

    public int getDefault1() {

36

        return default1;

37

    }

38

39

    public void setDefault1(int default1) {

40

        this.default1 = default1;

41

    }

42

}

 

 

 

 

store(OutputStreamout,Stringcomments)

我们知道直接 new FileOutputStream这样创建对象,会覆盖原有的文件,那么我们想在原有的文件中续写内容怎么办呢?继续查阅FileOutputStream的API。发现在FileOutputStream的构造函数中,可以接受一个boolean类型的值,如果值true,就会在文件末位继续添加。

10.4 打印流

store(Writerwriter,Stringcomments)参数二:代表注释

1publicclassFileOutputStreamDemo2 {2publicstaticvoidmain(String[] args)throwsException {3Filefile=newFile("c:\file.txt");4FileOutputStream fos =newFileOutputStream(file,true);5String str ="rn" "itcast";6fos.write(str.getBytes;7fos.close();8}9}

10.4.1 概述

        平时我们在控制台打印输出,是调用print方法和println方法完成的,这两个方法都来自于java.io.PrintStream类,该类能够方便地打印各种数据类型的值,是一种便捷的输出方式。

load():通过输入流读取指定文件中的数据

1.1.3.IO异常的处理

10.4.2 PrintStream类

 

load(InputStreaminStream)load(Readerreader)

我们在开发中应该如何处理这些异常呢?

构造方法

  • `public PrintStream(String fileName) `: 使用指定的文件名创建一个新的打印流。

3、遍历数据

1publicclassFileOutputStreamDemo3 {2publicstaticvoidmain(String[] args) {34Filefile=newFile("c:\file.txt");5//定义FileOutputStream的引用6FileOutputStream fos =null;7try{8//创建FileOutputStream对象9fos =newFileOutputStream;10//写出数据11fos.write("abcde".getBytes;1213}catch(IOException e) {14System.out.println(e.toString() "----");15}finally{16//一定要判断fos是否为null,只有不为null时,才可以关闭资源17if(fos !=null) {18try{19fos.close();20}catch(IOException e) {21thrownewRuntimeException;22}23}24}25}26}

10.4.3 改变打印流向

public static void main(String[] args) throws IOException { // 调用系统的打印流,控制台直接输出97 System.out.println(97); // 创建打印流,指定文件的名称 PrintStream ps = new PrintStream("ps.txt"); // 设置系统的打印流流向,输出到ps.txt System.setOut(ps); // 调用系统的打印流,ps.txt中输出97 System.out.println(97); }

 

 

 

12

 

 

 

 

 

1

    public static void main(String[] args) throws IOException {

2

// 调用系统的打印流,控制台直接输出97

3

        System.out.println(97);

4

      

5

// 创建打印流,指定文件的名称

6

        PrintStream ps = new PrintStream("ps.txt");

7

      

8

      // 设置系统的打印流流向,输出到ps.txt

9

        System.setOut(ps);

10

      // 调用系统的打印流,ps.txt中输出97

11

        System.out.println(97);

12

    }

 

 

 

list():将集合中的所有数据输出到指定的流中(一般用于调试)

1.2.字节输入流Input

10.5 属性集

list(PrintStreamout)list(PrintWriterout)

1.2.1.读取数据read方法

10.5.1 概述

java.util.Properties 继承于Hashtable ,来表示一个持久的属性集。它使用键值结构存储数据,每个键及其对应值都是一个字符串。该类也被许多Java类使用,比如获取系统属性时,System.getProperties data-wiz-span="data-wiz-span"> 方法就是返回一个Properties data-wiz-span="data-wiz-span">对象。

stringPropertyNames():获取集合中键的集合(键的类型是String类型)

通过api查找 input 。 java.io.InputStream。 InputStream:字节输入流的超类。

10.5.2 Properties类

 

常见功能:

构造方法

  • public Properties() :创建一个空的属性列表。

  • ### 基本的存储方法

    • public Object setProperty(String key, String value) : 保存一对属性。

    • public String getProperty(String key) :使用此属性列表中指定的键搜索属性值。

    • public Set<String> stringPropertyNames() :所有键的名称的集合。

 

1.1.1  示例程序

int read():读取一个字节并返回,没有字节返回-1.

与流相关的方法

  • `public void load(InputStream inStream)`: 从字节输入流中读取键值对。

参数中使用了字节输入流,通过流对象,可以关联到某文件上,这样就能够加载文本中的数据了。文本数据格式:

public static void main(String[] args) throws FileNotFoundException { // 创建属性集对象 Properties pro = new Properties(); // 加载文本中信息到属性集 pro.load(new FileInputStream("read.txt")); // 遍历集合并打印 Set<String> strings = pro.stringPropertyNames(); for (String key : strings ) { System.out.println(key " -- " pro.getProperty(key)); } } 结果: filename=a.txt length=209385038 location=D:a.txt tips; 文本中的数据,必须是键值对形式,可以使用空格、等号、冒号等符号分隔

 

 

 

18

 

 

 

 

 

1

    public static void main(String[] args) throws FileNotFoundException {

2

        // 创建属性集对象

3

        Properties pro = new Properties();

4

        // 加载文本中信息到属性集

5

        pro.load(new FileInputStream("read.txt"));

6

        // 遍历集合并打印

7

        Set<String> strings = pro.stringPropertyNames();

8

        for (String key : strings ) {

9

          System.out.println(key " -- " pro.getProperty(key));

10

        }

11

     }

12

结果:

13

filename=a.txt

14

length=209385038

15

location=D:a.txt

16

17

tips;

18

    文本中的数据,必须是键值对形式,可以使用空格、等号、冒号等符号分隔

 

 

 

int read: 读取一定量的字节数,并存储到字节数组中,返回读取到的字节数。

10.6 Path接口和Files类

publicclass Demo {

用于读取文件的字节输入流对象:FileInputStream。

10.6.1 概述

  • java.nio.file.Paths :是一个类,该类通过转换路径字符串返回一个Path
  • java.nio.file.Path:是一个接口,表示系统相关的文件路径,用于在文件系统中定位文件的对象,可以替代File类。

  • `java.nio.file.Files`:是一个工具类,包含对文件、目录进行操作的静态方法。

public static void main(String[] args)throws IOException {

1publicclassFileInputStreamDemo {2publicstaticvoidmain(String[] args)throwsIOException {3Filefile=newFile("c:\file.txt");4//创建一个字节输入流对象,必须明确数据源,其实就是创建字节读取流和数据源相关联。5FileInputStream fis =newFileInputStream;6//读取数据。使用 read();一次读一个字节。7intch =0;8while((ch=fis.read{9System.out.println("ch=" ;10}11// 关闭资源。12fis.close();13}14}

10.6.2 便捷的文件操作

Paths类 使用Paths,获取Path对象,代码演示如下: Path path = Paths.get("D:\a.txt"); Files类 - 删除文件 public static void main(String[] args) throws IOException { // 获取Path Path path = Paths.get("D:\a.txt"); // 删除文件 Files.delete(path); } - 文件复制 public static void main(String[] args) throws IOException { // 获取Path Path src = Paths.get("D:\src.txt"); Path target = Paths.get("D:\target.txt"); //REPLACE_EXISTING:文件存在,就替换 Files.copy(src, target,StandardCopyOption.REPLACE_EXISTING); } - 逐行读取文件 public static void main(String[] args) throws IOException { // 获取path Path src = Paths.get("D:\read.txt"); // 创建字符流 BufferedReader reader = Files.newBufferedReader(src,StandardCharsets.UTF_8); // 读取字符 String line ; while((line = reader.readLine()) != null){ System.out.println(line); } // 释放资源 reader.close(); }

 

 

 

x

 

 

 

 

 

1

Paths类

2

3

使用Paths,获取Path对象,代码演示如下:

4

5

    Path path = Paths.get("D:\a.txt");

6

7

Files类

8

9

- 删除文件

10

11

    public static void main(String[] args) throws IOException {

12

      // 获取Path

13

        Path path = Paths.get("D:\a.txt");

14

      // 删除文件

15

        Files.delete(path);

16

    }

17

18

- 文件复制

19

20

    public static void main(String[] args) throws IOException {

21

      // 获取Path

22

      Path src = Paths.get("D:\src.txt");

23

      Path target = Paths.get("D:\target.txt");

24

    

25

        //REPLACE_EXISTING:文件存在,就替换

26

        Files.copy(src, target,StandardCopyOption.REPLACE_EXISTING);

27

    }

28

29

- 逐行读取文件

30

31

    public static void main(String[] args) throws IOException {

32

      // 获取path

33

     Path src = Paths.get("D:\read.txt");

34

      // 创建字符流

35

        BufferedReader reader = Files.newBufferedReader(src,StandardCharsets.UTF_8);

36

      // 读取字符

37

        String line ;

38

        while((line = reader.readLine()) != null){

39

            System.out.println(line);

40

        }

41

      // 释放资源

42

        reader.close();

43

    }

44

45

46

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">

 

 

 

 

来自为知笔记(Wiz)

Properties prop = newProperties();

1.2.2.读取数据read方法

/*

在读取文件中的数据时,调用 read 方法,每次只能读取一个,太麻烦了,于是我们可以定义数组作为临时的存储容器,这时可以调用重载的 read 方法,一次可以读取多个字符。

* Properties类继承于Hashtable类,所以可以使用put方法添加键值对,

1publicclassFileInputStreamDemo2 {2publicstaticvoidmain(String[] args)throwsIOException {3/*

* 但是Properties类中的数据要求应该都是String类型,使用put方法返回可能会出问题

4 * 演示第二个读取方法, read;

* 官方建议使用setProperty()方法添加键值对

5 */6Filefile=newFile("c:\file.txt");7// 创建一个字节输入流对象,必须明确数据源,其实就是创建字节读取流和数据源相关联。8FileInputStream fis =newFileInputStream;9//创建一个字节数组。10byte[] buf =newbyte[1024];//长度可以定义成1024的整数倍。 11intlen =0;12while((len=fis.read!=-1){13System.out.println(newString(buf,0,len));14}15fis.close();16}17}

*/

2.字符流

//               prop.put("textsize",18);

经过前面的学习,我们基本掌握的文件的读写操作,在操作过程中字节流可以操作所有数据,可是当我们操作的文件中有中文字符,并且需要对中文字符做出处理时怎么办呢?

//               prop.get("textsize");

2.1.字节流读取问题

//保存值

通过以下程序读取带有中文件的文件。

prop.setProperty("textsize","18");

1publicclassCharStreamDemo{2publicstaticvoidmain(String[] args)throwsIOException{3//给文件中写中文4writeCNText();5//读取文件中的中文6readCNText();7}8//读取中文9publicstaticvoidreadCNText()throwsIOException{10FileInputStream fis =newFileInputStream("c:\cn.txt");11intch =0;12while((ch = fis.read{13System.out.println;14}15}16//写中文17publicstaticvoidwriteCNText()throwsIOException{18FileOutputStream fos =newFileOutputStream("c:\cn.txt");19fos.write("a传智播客欢迎你".getBytes;20fos.close();21}22}

prop.setProperty("textcolor","red");

上面程序在读取含有中文的文件时,我们并没有看到具体的中文,而是看到一些数字,这是什么原因呢?既然看不到中文,那么我们如何对其中的中文做处理呢?要解决这个问题,我们必须研究下字符的编码过程。

//获取值

2.2.编码表

String size =prop.getProperty("textsize");

我们知道计算机底层数据存储的都是二进制数据,而我们生活中的各种各样的数据,如何才能和计算机中存储的二进制数据对应起来呢?这时老美他们就把每一个字符和一个整数对应起来,就形成了一张编码表,老美他们的编码表就是ASCII表。其中就是各种英文字符对应的编码。

String color=prop.getProperty("textcolor");

编码表:其实就是生活中字符和计算机二进制的对应关系表。

System.out.println(size);

1、ascii: 一个字节中的7位就可以表示。对应的字节都是正数。0-xxxxxxx

System.out.println(color);

2、iso8859-1:拉丁码表 latin,用了一个字节用的8位。1-xxxxxxx 负数。

//将属性保存到磁盘上

3、GB2312:简体中文码表。包含6000-7000中文和符号。用两个字节表示。两个字节都是开头为1 ,两个字节都是负数。

//Properties的作用是将数据持久化保存,实际上就是将数据保存在磁盘上

GBK:目前最常用的中文码表,2万的中文和符号。用两个字节表示,其中的一部分文字,第一个字节开头是1,第二字节开头是0

//               prop.save(out, comments);

GB18030:最新的中文码表,目前还没有正式使用。

FileOutputStream fos = new FileOutputStream("prop.properties");

4、unicode:国际标准码表:无论是什么文字,都用两个字节存储。

prop.store(fos, "注释");

Java中的char类型用的就是这个码表。char c = 'a';占两个字节。

//从磁盘上读取属性数据

Java中的字符串是按照系统默认码表来解析的。简体中文版 字符串默认的码表是GBK。

Properties prop2 = newProperties();

5、UTF-8:基于unicode,一个字节就可以存储数据,不要用两个字节存储,而且这个码表更加的标准化,在每一个字节头加入了编码信息(后期到api中查找)。

FileInputStream fis = newFileInputStream("prop.properties");

能识别中文的码表:GBK、UTF-8;正因为识别中文码表不唯一,涉及到了编码解码问题。对于我们开发而言;常见的编码 GBK UTF-8 ISO8859-1

prop2.load(fis);

文字---> :编码。

System.out.println(prop2);

--->文字 : 解码。

//遍历Properties集合(是Map集合)

2.3.FileReader类介绍

//list方法一般是用于调试用的

上述程序中我们读取拥有中文的文件时,使用的字节流在读取,那么我们读取到的都是一个一个字节。只要把这些字节去查阅对应的编码表,就能够得到与之对应的字符。API中是否给我们已经提供了读取相应字符的功能流对象呢?

prop2.list(System.out);

查阅FileInputStream的 API ,发现 FileInputStream 用于读取诸如图像数据之类的原始字节流。要读取字符流,请考虑使用 FileReader 。如果读取字符流,要使用 FileReader , FileReader 是什么呢?

//传统的遍历Map集合的方式,通过keyset方法获取键的集合,但是元素都是Object类型

打开FileReader的 API 介绍。用来读取字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是适当的,原来FileReader 用于读取字符流。使用 FileReader 时,了解它的功能,看它所属的体系顶层。

//               prop2.keySet();

Reader:读取字符流的抽象超类。

Set     keyset = prop2.stringPropertyNames();

read():读取单个字符并返回

for (String key : keyset) {

read:将数据读取到数组中,并返回读取的个数。

String value =prop2.getProperty(key);

1publicclassCharStreamDemo{2publicstaticvoidmain(String[] args)throwsIOException{3//给文件中写中文4writeCNText();5//读取文件中的中文6readCNText();7}8//读取中文9publicstaticvoidreadCNText()throwsIOException{10FileReader fr =newFileReader("D:\test\cn.txt");11intch =0;12while((ch = fr.read{13//输出的字符对应的编码值14System.out.println;15//输出字符本身16System.out.println;17}18}19//写中文20publicstaticvoidwriteCNText()throwsIOException{21FileOutputStream fos =newFileOutputStream("D:\test\cn.txt");22fos.write("a传智播客欢迎你".getBytes;23fos.close();24}25}

System.out.println(key "..........." value);

2.4.FileWriter类介绍

}

既然有专门用于读取字符的流对象,那么肯定也有写的字符流对象,查阅 API ,发现有一个Writer 类, Writer 是写入字符流的抽象类。其中描述了相应的写的动作。

}

1publicclassFileWriterDemo{2publicstaticvoidmain(String[] args)throwsIOException{3//演示FileWriter 用于操作文件的便捷类。4FileWriter fw =newFileWriter("d:\text\fw.txt");56fw.write;//这些文字都要先编码。都写入到了流的缓冲区中。78fw.flush();910fw.close();11}12}

}

2.5.flush的区别

实例:写一个程序,要求用户只能打开5次,在第6次打开的时候就抛出异常提示“打开失败”

flush(): 将流中的缓冲区缓冲的数据刷新到目的地中,刷新后,流还可以继续使用。

publicclass Ex {

close(): 关闭资源,但在关闭前会将缓冲区中的数据先刷新到目的地,否则丢失数据,然后在关闭流。流不可以使用。如果写入数据多,一定要一边写一边刷新,最后一次可以不刷新,由 close 完成刷新并关闭。

public static void main(String[] args){

3.转换流

System.out.println("程序开启.......");

学习完了使用字符流对文件的简单操作后,在学习字符流的时候,其中说如果需要指定编码和缓冲区大小时,可以在字节流的基础上,构造一个 InputStreamReader 或者 OutputStreamWriter ,这又是什么意思呢?

//检测使用的次数

3.1.OutputSreamWriter类

check();

需求:既然识别中文的码表有两个, GBK 、 UTF-8 等,能不能将中文数据按照 utf-8 的方式进行文件的存储呢?

System.out.println("程序正常运行.......");

还能使用 FileWriter 吗?不能使用了,因为 FileWriter 中默认的是 GBK 。通过 FileWriter 的api 描述,要指定编码表这些值,需要使用 OutputStreamWriter

System.out.println("程序结束.......");

OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。它的作用的就是,将字符串按照指定的编码表转成字节,在使用字节流将这些字节写出去。

}

1publicstaticvoidwriteCN()throwsException{2//创建与文件关联的字节输出流对象3FileOutputStream fos =newFileOutputStream("c:\cn8.txt");4//创建可以把字符转成字节的转换流对象,并指定编码5OutputStreamWriter osw =newOutputStreamWriter(fos,"utf-8");6//调用转换流,把文字写出去,其实是写到转换流的缓冲区中7osw.write;//写入缓冲区。8osw.close();9}

private static void check() {

OutputStreamWriter 流对象,它到底如何把字符转成字节输出的呢?

/*

其实在 OutputStreamWriter 流中维护自己的缓冲区,当我们调用 OutputStreamWriter 对象的write 方法时,会拿着字符到指定的码表中进行查询,把查到的字符编码值转成字节数存放到 OutputStreamWriter 缓冲区中。然后再调用刷新功能,或者关闭流,或者缓冲区存满后会把缓冲区中的字节数据使用字节流写到指定的文件中。

* 思路:记录用户打开程序的次数,每次打开的时候都记一次,将次数保存在配置文件中,

3.2.InputSreamReader类

* 每次打开的时候读取上一次记录的次数,如果超出上限,就提示用户

查阅 InputStreamReader 的 API 介绍, InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。

*/

1publicclassInputStreamReaderDemo{2publicstaticvoidmain(String[] args) throws IOException{3//演示字节转字符流的转换流4readCN();5}6publicstaticvoidreadCN() throws IOException{7//创建读取文件的字节流对象8InputStreamin=newFileInputStream("c: \cn8.txt");9//创建转换流对象 10//InputStreamReader isr = new InputStreamReader;这样创建对象,会用本地默认码表读取,将会发生错误解码的错误11InputStreamReader isr =newInputStreamReader(in,"utf-8");12//使用转换流去读字节流中的字节13intch =0;14while((ch = isr.read{15System.out.println;16}17//关闭流18isr.close();19}20}

//

注意:在读取指定的编码的文件时,一定要指定编码格式,否则就会发生解码错误,而发生乱码现象。

FileInputStream fis =null;

3.3.转换流和子类的区别

FileOutputStream fos = null;

发现有如下继承关系:

try {

OutputStreamWriter:

Properties prop =new Properties();

FileWriter:

File file = newFile("prop_ex.properties");

InputStreamReader:

//要保证文件存在

FileReader;

if(!file.exists()){

父类和子类的功能有什么区别呢?

file.createNewFile();

OutputStreamWriter和InputStreamReader是字符和字节的桥梁:也可以称之为字符转换流。字符转换流原理:字节流 编码表。

}

FileWriter和FileReader:作为子类,仅作为操作字符文件的便捷类存在。当操作的字符文件,使用的是默认编码表时可以不用父类,而直接用子类就完成操作了,简化了代码。

fis = new FileInputStream(file);

InputStreamReader isr = new InputStreamReader(new FileInputStream;//默认字符集。

//从文件中加载数据到Properties集合中

InputStreamReader isr = new InputStreamReader(new FileInputStream,"GBK");//指定GBK字符集。

prop.load(fis);

FileReader fr = new FileReader;

//通过键获取值,如果键值对不存在,就返回指定的默认值

这三句代码的功能是一样的,其中第三句最为便捷。

int count=Integer.parseInt(prop.getProperty("count","0"));

注意:一旦要指定其他编码时,绝对不能用子类,必须使用字符转换流。什么时候用子类呢?

count ;

条件:

//判断打开的次数是否已经超过了上限

1、操作的是文件。2、使用默认编码。3 纯文本

if(count>5){

总结:

throw newRuntimeException("适用用次数已经超过5次上限,请续费!.......");

字节--->字符 : 看不懂的--->看的懂的。 需要读。输入流。 InputStreamReader

}else{

字符--->字节 : 看的懂的--->看不懂的。 需要写。输出流。 OutputStreamWriter

//如果没有超过

4.缓冲流

fos = newFileOutputStream(file);

在我们学习字节流与字符流的时候,大家都进行过读取文件中数据的操作,读取数据量大的文件时,读取的速度会很慢,很影响我们程序的效率,那么, 我想提高速度,怎么办? Java 中提高了一套缓冲流,它的存在,可提高 IO 流的读写速度 缓冲流,根据流的分类分类字节缓冲流与字符缓冲流。

prop.setProperty("count",String.valueOf(count));

4.1.字节缓冲流

prop.store(fos,"open count");

字节缓冲流根据流的方向,共有 2 个

}

写入数据到流中,字节缓冲输出流 BufferedOutputStream

} catch (IOException e) {

读取流中的数据,字节缓冲输入流 BufferedInputStream

// TODO: handleexception

它们的内部都包含了一个缓冲区,通过缓冲区读写,就可以提高了 IO流的读写速度

}finally{

4.1.1.字节缓冲输出流BufferedOutputStream

if(fos != null){

通过字节缓冲流,进行文件的读写操作 写数据到文件的操作

try {

构造方法public BufferedOutputStream(OutputStream out)创建一个新的缓冲输出流,以将数据写入指定的底层输出流。

fos.close();

1publicclassBufferedOutputStreamDemo01{2publicstaticvoidmain(String[] args) throws IOException{34//写数据到文件的方法5write();6}78/*

fos= null;

9 * 写数据到文件的方法

} catch(IOException e) {

10 * 1,创建流

//TODO Auto-generated catch block

11 * 2,写数据

e.printStackTrace();

12 * 3,关闭流

}

13 */14privatestaticvoidwrite() throws IOException{15//创建基本的字节输出流16FileOutputStream fileOut =newFileOutputStream("abc.txt");17//使用高效的流,把基本的流进行封装,实现速度的提升18BufferedOutputStreamout=newBufferedOutputStream;19//2,写数据20out.write("hello".getBytes;21//3,关闭流22out.close();23}24}

}

4.1.2.字节缓冲输出流BufferedInputStream

if(fis != null){

刚刚我们学习了输出流实现了向文件中写数据的操作,那么,现在我们完成读取文件中数据的操作

try {

构造方法

fis.close();

public BufferedInputStream(InputStream in)

fis= null;

1/*

} catch(IOException e) {

2 * 从文件中读取数据

//TODO Auto-generated catch block

3 * 1,创建缓冲流对象

e.printStackTrace();

4 * 2,读数据,打印

}

5 * 3,关闭

}

6 */7privatestaticvoidread() throws IOException{8//1,创建缓冲流对象9FileInputStream fileIn =newFileInputStream("abc.txt");10//把基本的流包装成高效的流11BufferedInputStreamin=newBufferedInputStream;12//2,读数据13intch =-1;14while( (ch =in.read {15//打印16System.out.print;17}18//3,关闭19in.close();20}

}

4.1.3.使用基本的流与高效的流完成复制文件

}

我们一直在说,高效的流速度快并高效,怎么体现呢?需要通过一个复制文件耗时的比较过程,来体验一下高效流带来的快感。

}

1/*

2 * 需求:将d:\test.avi文件进行复制

1.2    内存流

3 * 采用4种方式复制

4 * 方式1: 采用基本的流,一次一个字节的方式复制 共耗时 224613毫秒

数组流

5 * 方式2: 采用基本的流,一个多个字节的方式赋值 共耗时 327毫秒

6 * 方式3: 采用高效的流,一次一个字节的方式复制 共耗时 2047毫秒

7 * 方式4: 采用高效的流,一个多个字节的方式赋值 共耗时 96毫秒

byte[] bytes ={97,98,99,100,101};//源字节数组

8 *

ByteArrayInputStream bais =//在源数组上创建一个内存输入流

9 * 数据源: d:\test.avi

newByteArrayInputStream(bytes);

10 * 目的地1: d:\copy1.avi

int n=0;

11 * 目的地2: d:\copy2.avi

byte[] buf = new byte[4];

12 * 目的地3: d:\copy3.avi

//读4个字节放到缓冲buf中,返回有效读取数

13 * 目的地4: d:\copy4.avi

while((n=bais.read(buf))!=-1){

14 *

for(int i=0;i

15 * 实现的步骤:

System.out.println(buf[i]);  //打印

16 * 1,指定数据源

}

17 * 2,指定目的地

}

18 * 3,读数据

}

19 * 4,写数据

//不需要关闭

20 * 5,关闭流

//创建一个内存输出流,可以通过它向内置的字节数组中写字节

21 *

ByteArrayOutputStream baos=new ByteArrayOutputStream();

22 */23publicclassCopyAVI{24publicstaticvoidmain(String[] args) throws IOException{25//开始计时26longstart = System.currentTimeMillis();27//方式1: 采用基本的流,一次一个字节的方式复制28//method1("d:\test.avi", "d:\copy1.avi");29//方式2: 采用基本的流,一个多个字节的方式赋值30//method2("d:\test.avi", "d:\copy2.avi");31//方式3: 采用高效的流,一次一个字节的方式复制32//method3("d:\test.avi", "d:\copy3.avi");33//方式4:

baos.write(65);//往内置字节数组中写一个字节

采用高效的流,一个多个字节的方式赋值34method4("d:\test.avi","d:\copy4.avi");3536//结束计时37longend

System.currentTimeMillis();38//打印耗时多少毫秒39System.out.println("共耗时 " (end - start) "毫秒");40}4142//方式4: 采用高效的流,一个多个字节的方式赋值43privatestaticvoidmethod4(String src, String dest) throws IOException{44//1,指定数据源45BufferedInputStreamin=newBufferedInputStream(newFileInputStream;46//2,指定目的地47BufferedOutputStreamout=newBufferedOutputStream(newFileOutputStream;48//3,读数据49byte[] buffer =newbyte[1024];50intlen =-1;51while( (len =in.read !=-1) {52//4,写数据53out.write(buffer,0, len);54}55//5,关闭流56in.close();57out.close();58}5960//方式3: 采用高效的流,一次一个字节的方式复制61privatestaticvoidmethod3(String src, String dest) throws IOException{62//1,指定数据源63BufferedInputStreamin=newBufferedInputStream(newFileInputStream;64//2,指定目的地65BufferedOutputStreamout=newBufferedOutputStream(newFileOutputStream;66//3,读数据67intch =-1;68while((ch=in.read {69//4,写数据70out.write;71}72//5,关闭流73in.close();74out.close();75}7677//方式2: 采用基本的流,一个多个字节的方式赋值78privatestaticvoidmethod2(String src, String dest) throws IOException{79//1,指定数据源80FileInputStreamin=newFileInputStream;81//2,指定目的地82FileOutputStreamout=newFileOutputStream;83//3,读数据84byte[] buffer =newbyte[1024];85intlen =-1;86while( (len=in.read !=-1) {87//4,写数据88out.write(buffer,0, len);89}90//5,关闭流91in.close();92out.close();93}9495//方式1: 采用基本的流,一次一个字节的方式复制96privatestaticvoidmethod1(String src, String dest) throws IOException{97//1,指定数据源98FileInputStreamin=newFileInputStream;99//2,指定目的地100FileOutputStreamout=newFileOutputStream;101//3,读数据102intch =-1;103while(( ch=in.read {104//4,写数据105out.write;106}107//5,关闭流108in.close();109out.close();110}111}

4.2.字符缓冲流

字符缓冲输入流 BufferedReader

字符缓冲输出流 BufferedWriter

完成文本数据的高效的写入与读取的操作

4.2.1.字符缓冲输出流BufferedWriter

将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。

方法:void newLine() 根据当前的系统,写入一个换行符

1/*

2 * BufferedWriter 字符缓冲输出流

3 * 方法

4 * public void newLine()写入一个行分隔符

5 *

6 * 需求: 通过缓冲输出流写入数据到文件

7 * 分析:

8 * 1,创建流对象

9 * 2,写数据

10 * 3,关闭流

11 *

12 */13publicclassBufferedWriterDemo{14publicstaticvoidmain(String[] args) throws IOException{15//创建流16//基本字符输出流17FileWriter fileOut =newFileWriter("file.txt");18//把基本的流进行包装19BufferedWriterout=newBufferedWriter;20//2,写数据21for(inti=0; i<5; i ) {22out.write;23out.newLine();24}25//3,关闭流26out.close();27}28}

4.2.2.字符缓冲输入流BufferedReader

从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。

方法public readLine () 读取一个文本行, 包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null

1/*

2 * BufferedReader 字符缓冲输入流

3 *

4 * 方法:

5 * String readLine()

6 * 需求:从文件中读取数据,并显示数据

7 */8publicclassBufferedReaderDemo{9publicstaticvoidmain(String[] args) throws IOException{10//1,创建流11BufferedReaderin=newBufferedReader(newFileReader("file.txt"));12//2,读数据13//一次一个字符14//一次一个字符数组15//一次读取文本中一行的字符串内容16String line =null;17while( (line =in.readLine !=null){18System.out.println;19}2021//3,关闭流22in.close();23}24}

4.2.3.使用字符缓冲流完成文本文件的复制

刚刚我们学习完了缓冲流,现在我们就使用字符缓冲流的特有功能,完成文本文件的复制

1/*

2 * 采用高效的字符缓冲流,完成文本文件的赋值

3 *

4 * 数据源: file.txt

5 * 目的地: copyFile.txt

6 *

7 * 分析:

8 * 1,指定数据源, 是数据源中读数据,采用输入流

9 * 2,指定目的地,是把数据写入目的地,采用输出流

10 * 3,读数据

11 * 4,写数据

12 * 5,关闭流

13 */14publicclassCopyTextFile{15publicstaticvoidmain(String[] args) throws IOException{16//1,指定数据源, 是数据源中读数据,采用输入流17BufferedReaderin=newBufferedReader(newFileReader("file.txt"));18//2,指定目的地,是把数据写入目的地,采用输出流19BufferedWriterout=newBufferedWriter(newFileWriter("copyFile.txt"));20//3,读数据21String line =null;22while( (line =in.readLine !=null) {23//4,写数据24out.write;25//写入换行符号26out.newLine();27}28//5,关闭流29out.close();30in.close();31}32}

5.Properties类

5.1. Properties类介绍

Properties特点:

1 、 Hashtable 的子类, map 集合中的方法都可以用。

2 、该集合没有泛型。键值都是字符串。

3 、它是一个可以持久化的属性集。键值可以存储到集合中,也可以存储到持久化的设备 ( 硬盘、 U 盘、光盘 ) 上。键值的来源也可以是持久化的设备。

4 、有和流技术相结合的方法。

a.load(InputStream) 把指定流所对应的文件中的数据,读取出来,保存到Propertie集合中

b. load

c. store(OutputStream,commonts)把集合中的数据,保存到指定的流所对应的文件中,参数commonts代表对描述信息

d.stroe(Writer,comments);

1/*

2 *

3 * Properties集合,它是唯一一个能与IO流交互的集合

4 *

5 * 需求:向Properties集合中添加元素,并遍历

6 *

7 * 方法:

8 * public Object setProperty(String key, String value)调用 Hashtable 的方法 put。

9 * public Set<String> stringPropertyNames()返回此属性列表中的键集,

10 * public String getProperty(String key)用指定的键在此属性列表中搜索属性

11 */12publicclassPropertiesDemo01{13publicstaticvoidmain(String[] args){14//创建集合对象15Properties prop =newProperties();16//添加元素到集合17//prop.put(key, value);18prop.setProperty("周迅","张学友");19prop.setProperty("李小璐","贾乃亮");20prop.setProperty("杨幂","刘恺威");2122//System.out.println;//测试的使用23//遍历集合24Set keys = prop.stringPropertyNames();25for(String key : keys) {26//通过键 找值27//prop.get28Stringvalue= prop.getProperty;29System.out.println(key "==" value);30}31}32}

将配置文件中的数据存储到文件中

1/**

2 * 需求:使用Properties集合,完成把集合内容存储到IO流所对应文件中的操作

3 *

4 * 分析:

5 * 1,创建Properties集合

6 * 2,添加元素到集合

7 * 3,创建流

8 * 4,把集合中的数据存储到流所对应的文件中

9 * store(OutputStream,commonts)把集合中的数据,保存到指定的流所对应的文件中,参数commonts代表对描述信息

10 * stroe(Writer,comments);

11 * 5,关闭流

12 */13publicclassPropertiesDemo02{14publicstaticvoidmain(String[] args) throws IOException{15//1,创建Properties集合16Properties prop =newProperties();17//2,添加元素到集合18prop.setProperty("周迅","张学友");19prop.setProperty("李小璐","贾乃亮");20prop.setProperty("杨幂","刘恺威");2122//3,创建流23FileWriterout=newFileWriter("prop.properties");24//4,把集合中的数据存储到流所对应的文件中25prop.store(out,"save data");26//5,关闭流27out.close();28}29}

读取配置文件中的数据,同时更新数据,并保存

1/*

2 * 需求:从属性集文件prop.properties 中取出数据,保存到集合中

3 * 分析:

4 * 1,创建集合

5 * 2,创建流对象

6 * 3,把流所对应文件中的数据 读取到集合中

7 * load(InputStream) 把指定流所对应的文件中的数据,读取出来,保存到Propertie集合中

8 load

9 * 4,关闭流

10 * 5,显示集合中的数据

11 */12publicclassPropertiesDemo03{13publicstaticvoidmain(String[] args) throws IOException{14//1,创建集合15Properties prop =newProperties();16//2,创建流对象17FileInputStreamin=newFileInputStream("prop.properties");18//FileReader in = new FileReader("prop.properties");19//3,把流所对应文件中的数据 读取到集合中20prop.load;21//4,关闭流22in.close();23//5,显示集合中的数据24System.out.println;2526}

注意:使用字符流 FileReader 就可以完成文件中文的读取操作了

6.序列化流与烦序列化流

6.1.对象序列化流

用于从流中读取对象的操作流 ObjectInputStream 称为 反序列化流

用于向流中写入对象的操作流 ObjectOutputStream 称为 序列化流

特点:用于操作对象。

解决问题:可以将对象进行序列化和反序列化。

注意:对象序列化一定要实现Serializable接口。为了给类定义一个 serialVersionUID 。

功能:

ObjectInputStream readObject()

ObjectOutputStream writeObject()

1publicclassObjectStreamDemo{2publicstaticvoidmain(String[] args)throwsIOException, ClassNotFoundException{3/*

4 * 将一个对象存储到持久化的设备上。

5 */6writeObj();//对象的序列化。7}8publicstaticvoidwriteObj()throwsIOException{9//1,明确存储对象的文件。10FileOutputStream fos =newFileOutputStream("tempfile\obj.object");11//2,给操作文件对象加入写入对象功能。12ObjectOutputStream oos =newObjectOutputStream;13//3,调用了写入对象的方法。14oos.writeObject(newPerson("wangcai",20));15//关闭资源。16oos.close();17}18}

6.2.对象反序列化流

当把一个对象持久化存储起来之后,需要使用反序列化技术获取存储起来的对象。 使用此 ObjectInputStream 对象就可以完成反序列化动作

1publicclassObjectStreamDemo{2publicstaticvoidmain(String[] args)throwsIOException, ClassNotFoundException{3readObj();//对象的反序列化。4}5publicstaticvoidreadObj()throwsIOException, ClassNotFoundException{67//1,定义流对象关联存储了对象文件。8FileInputStream fis =newFileInputStream("tempfile\obj.object");910//2,建立用于读取对象的功能对象。11ObjectInputStream ois =newObjectInputStream;1213Person obj = ois.readObject();1415System.out.println(obj.toString;1617}18}

6.3.序列化接口

当一个对象要能被序列化,这个对象所属的类必须实现Serializable 接口。否则会发生异常 NotSerializableException 异常。

同时当反序列化对象时,如果对象所属的 class 文件在序列化之后进行的修改,那么进行反序列化也会发生异常 InvalidClassException 。发生这个异常的原因如下:

该类的序列版本号与从流中读取的类描述符的版本号不匹配

该类包含未知数据类型

该类没有可访问的无参数构造方法

Serializable 标记接口。该接口给需要序列化的类,提供了一个序列版本号。 serialVersionUID. 该版本号的目的在于验证序列化的对象和对应类是否版本匹配。

1publicclassPersonimplementsSerializable{23//给类显示声明一个序列版本号。4privatestaticfinallongserialVersionUID =1L;5privateString name;6privateintage;7publicPerson(){8super();910}11publicPerson(String name,intage){12super();13this.name = name;14this.age = age;15}1617publicStringgetName(){18returnname;19}20publicvoidsetName(String name){21this.name = name;22}23publicintgetAge(){24returnage;25}26publicvoidsetAge{27this.age = age;28}29@Override30publicStringtoString(){31return"Person [name=" name ", age=" age "]";32}33}

7.总结

字节流

字节输入流 InputStream

FileInputStream 操作文件的字节输入流

BufferedInputStream高效的字节输入流

ObjectInputStream 反序列化流(操作对象的字节输入流)

字节输出流 OutputStram

FileOutputStream 操作文件的字节输出流

BufferedOutputStream 高效的字节输出流

ObjectOuputStream 序列化流(操作对象的字节输出流)

字符流

字符输入流 Reader

FileReader 操作文件的字符输入流

BufferedReader 高效的字符输入流

InputStreamReader 输入操作的转换流(把字节流封装成字符流)

字符输出流 Writer

FileWriter 操作文件的字符输出流

BufferedWriter 高效的字符输出流

OutputStreamWriter 输出操作的转换流(把字节流封装成字符流)

将字符流转换成字节流去存储

方法:

读数据方法:

read() 一次读一个字节或字符的方法

read(byte[] char[]) 一次读一个数组数据的方法

readLine() 一次读一行字符串的方法(BufferedReader类特有方法)

readObject() 从流中读取对象(ObjectInputStream特有方法)

写数据方法:

write 一次写一个字节或字符到文件中

write(byte[] char[]) 一次写一个数组数据到文件中

write 一次写一个字符串内容到文件中

writeObject 写对象到流中(ObjectOutputStream类特有方法)

newLine() 写一个换行符号(BufferedWriter类特有方法)

向文件中写入数据的过程

1,创建输出流对象

2,写数据到文件

3,关闭输出流

从文件中读数据的过程

1, 创建输入流对象

2, 从文件中读数据

3, 关闭输入流

文件复制的过程

1, 创建输入流

2, 创建输出流

3, 从输入流中读数据

4, 通过输出流,把数据写入目的地

5, 关闭流

Properties:Map集合的一种,它是Hashtable集合的子集合,它键与值都是String类型,它是唯一能与IO流结合使用的集合

方法

load( InputStream in ) 从流所对应的文件中,读数据到集合中

load( Reader in ) 从流所对应的文件中,读数据到集合中

store( OutputStream out , String message ) 把集合中的数据,写入到流所对应的文件中

store( Writer out , String message) 把集合中的数据,写入到流所对应的文件中

实现文件内容的自动追加

构造方法

FileOutputStream(File file, boolean append)

FileOutputStream(String fileName, boolean append)

FileWriter(File, boolean append)

FileWriter(String fileName, boolean append)

小编整理了一些java进阶学习资料和面试题,需要资料的请加JAVA高阶学习Q群:664389243 这是小编创建的java高阶学习交流群,加群一起交流学习深造。群里也有小编整理的2019年最新最全的java高阶学习资料!

baos.write(66);

baos.write(67);

//从中拿出之前写的字节生成的数组

byte[] array =baos.toByteArray();

for(byte b : array){//遍历打印,用于验证

System.out.println(b);

}

//源文件流

FileInputStream fis = newFileInputStream("g:/output.txt");

//目标内存输出流

ByteArrayOutputStream baos=new  ByteArrayOutputStream();

int n=0;

byte[] buf = new byte[4];//缓冲数组创建

//每次从文件读4个字节方法缓冲中,有效字节数赋给n,和-1比较判断是否读完

while((n=fis.read(buf))!=-1){

baos.write(buf,0,n);   //没有读完就将有效字节写到内存输出流

}

fis.close();//需要关闭

//               baos.close();//不需要关闭

byte[]array=baos.toByteArray();   //获取字节数组

for (byte b : array) {//遍历,验证

System.out.println((char)b);

}

FileInputStream fis =new FileInputStream(

"g:/MySQL-connector-Java-5.1.7-bin.jar");

ByteArrayOutputStream baos =new ByteArrayOutputStream();

int n = 0;

byte[] buf = newbyte[1024];//缓冲

while ((n = fis.read(buf)) !=-1) {//从文件读1024字节,有效字节数赋值给n,和-1比较判断是否结束

baos.write(buf, 0,n);//把有效字节写到内存输出流

}

fis.close();

byte[] array =baos.toByteArray(); //用写进的字节生成数组

//准备从这个字节数组中读字节

ByteArrayInputStream bais =new ByteArrayInputStream(array);

FileOutputStream fos = newFileOutputStream("g:/copy.jar");

while ((n = bais.read(buf))!= -1) {//从数组读1024字节,有效字节数赋给n,和-1比较

fos.write(buf, 0,n); //把有效字节写到copy.jar

}

fos.close();

FileInputStream fis = newFileInputStream("g:/mysql-connector-java-5.1.7-bin.jar");

ByteArrayOutputStream baos=new ByteArrayOutputStream();

int n= 0;

byte[] buf = new byte[1024];

while((n=fis.read(buf))!=-1){//读源文件只进行一次

baos.write(buf,0,n);

}

fis.close();

byte[] array =baos.toByteArray();

//把文件放到内存中,这些动作不重复进行,这些动作包含了对磁盘的操作

//把内存中的内容拷贝到文件,重复进行

for(int i=1;i<=100;i ){

ByteArrayInputStreambais = new ByteArrayInputStream(array);

FileOutputStream fos= new FileOutputStream("g:/100/" i ".jar");

//这里也要读100次,但是每次都是读内存数组,所以效率大大提高

while((n=bais.read(buf))!=-1){

fos.write(buf,0,n);

}

fos.close();

}

内存流(字节数组)节点流、字节流

ByteArrayInputStream

ByteArrayOutputStream

构造方法:

ByteArrayInputStream(byte[]bytes)创建一个内存流,可以从参数字节数组中读取字节

常用方法:

int read()

int read(byte[] buf)

不需要调用close()方法

构造方法:

ByteArrayOutputStream()创建一个内存输出流,无参数,可以往内置的字节数组中写字节

常用方法:

write(int b)

write(byte[] buf,intoff,int len)

不需要调用close()方法

toByteArray()获得字节数组(之前写到其中的字节组成的字节数组)

在文件小且不经常变更的情况下,可以用内存流先进行缓存,避免反复磁盘操作

实例:

public static void main(String[] args)throws IOException {

//字节数组输出流

//是以数组作为数据源,将数据写到数组中

//当数组输出流被创建的时候内部会自动创建一个数组

ByteArrayOutputStream baso =new ByteArrayOutputStream();

//将数据写出到数组流内部的数组(内存)中

baso.write("强风125".getBytes());

//取出流中的字节数组

byte[]buf  =baso.toByteArray();

System.out.println(newString(buf));

//在这里因为操作的是内存,所以不需要释放存放

//               baso.close();

//使用场景:从网上下载图片并显示在界面上

//从内存数组中去数据

ByteArrayInputStream bais =new ByteArrayInputStream(buf);

byte[] cubf  = new byte[1024];

bais.read(cubf);

System.out.println(newString(cubf));

//如果一个数组中的数据比较多,需要分批读取,那么使用数组流能简化我们的代码

//比如:现在有一个字节数组大小为1000,每次读取300个字节,自到将数据读完

}

1.3    对象流

对象流是一种处理流、字节流

对象流

ObjectInputStream

readObject()

ObjectOutputStream

writeObject()

注意事项:

1、被对象流操作的对象必须先进行序列化(实现Serializable接口)

1)需要在类中定义一个静态常量(序列值,static final longserialVersionUID)

2)在数据序列化的时候不会对静态字段(static )和瞬态字段(transient)进行序列化

2、一个文件只能存储一个对象

实例:

publicclass Demo {

public static void main(String[] args)throws IOException, ClassNotFoundException {

//               test1();

//               writeObj();

readObj();

}

private static void readObj() throwsIOException, ClassNotFoundException {

FileInputStream fis = newFileInputStream("objdemo.object");

ObjectInputStream ois = new ObjectInputStream(fis);

//内部自动进行了反序列化

Student stu =(Student)ois.readObject();

System.out.println(stu);

}

private static void writeObj() throwsIOException {

Student stu = new Student("小强", "男", 18);

//对象流,用于直接操作对象

FileOutputStream fos = newFileOutputStream("objdemo.object");

ObjectOutputStream oos = newObjectOutputStream(fos);

//将对象写出到指定设备

//注意:对象流操作的对象必须进行序列化

//序列化:只需要实现Serializable

oos.writeObject(stu);

oos.close();

}

private static void test1() throwsIOException, FileNotFoundException {

Student stu = newStudent("小强","男", 18);

FileWriter fw =  newFileWriter("object.txt");

fw.write(stu.name "|");

fw.write(stu.gender "|");

fw.write(stu.age "");

fw.close();

//从磁盘上读取对象的数据并生成对象

BufferedReader br = new BufferedReader(newFileReader("object.txt"));

String line = br.readLine();

String[] strs = line.split("\|");

String name = strs[0];

String gender = strs[1];

int age = Integer.parseInt(strs[2]);

Student stu2 = new Student(name, gender, age);

System.out.println(stu2);

}

}

classStudent implements Serializable/*标记接口*/{

/**

* 序列值,用于标记类的唯一性

* 如果没有指定序列值,那么编译器会自动根据类中的成员来自动生成一个序列值

* 建议:在序列化的时候最好要写上序列值

*/

private static final long serialVersionUID= 10000L;

/**

* static 修饰的类成员不会被序列化

*/

String name;

String gender;

transient int age;     //瞬态的(不会进行序列化)

public Student(String name, Stringgender, int age) {

this.name = name;

this.gender = gender;

this.age = age;

}

@Override

public String toString() {

return "Student[name=" name ", gender=" gender ", age=" age

"]";

}

}

1.3.1  ObjectOutputStream

//文件的文件输出流

FileOutputStream fos = newFileOutputStream("g:/obj");

//用对象输出流去处理、装饰fos文件输出流

ObjectOutputStream oos = newObjectOutputStream(fos);

oos.writeObject("1000phone");//写一个字符串对象到流中

oos.close();

//对象流装饰文件流

ObjectOutputStream oos = newObjectOutputStream(

newFileOutputStream("g:/elephant"));

//初始化对象

Elephant mike = newElephant("Mike", 1000);

oos.writeObject(mike);    //把大象塞进去

oos.close();

构造方法:ObjectOutputStream(OutputStream os)参数是它要处理、装饰的流,增加了写对象的功能

writeObject(Objectobj)

1.3.2  ObjectInputStream

ObjectInputStream ois= //用对象流装饰文件流

newObjectInputStream(new FileInputStream("g:/obj"));

String str =(String)ois.readObject();   //读一个对象

System.out.println("从obj文件中拿出来了:" str);

ois.close();

ObjectInputStream ois= new ObjectInputStream(

newFileInputStream("g:/elephant"));

//把大象从流中拖出来,拿到的是Object类型,强转为大象类型

Elephant e =(Elephant)ois.readObject();

System.out.println(e.getName() "   " e.getWeight());

ois.close();

构造方法:ObjectInputStream(InputStream is)参数是它要处理、装饰的流,增加了读对象的功能

Object readObject()

对象流读写,写的和读的类型一定要一致。

对象流读写的对象必须要可序列化,必须实现Serializable接口,这个接口无抽象方法。

用途:信息的存储、信息在网络上的传递、信息在组件间传递

1.4    输出流(打印流)

PrintWriterpw = new PrintWriter(

newFileOutputStream("g:/answer.txt",true));

//由于构造方法第二个参数为true ,println会自动刷缓存

pw.println("1000phone");//打印1000phone到文件中并换行

pw.println("Android");//打印android到文件中并换行

pw.println("java");//打印java到文件中并换行

pw.close();

PrintWriter输出流、字符流、处理流

构造方法:

PrintWriter(OutputStreamos,boolean autoFlush)第一个参数是所要装饰的字节输出流,第二个参数是表示是否自动刷缓存

PrintWriter(Writerwriter,boolean autoFlush)装饰字符流

PrintWriter(Stringpath,String csn)在以第一个参数为路径的文件上建立打印流,字符集由第二个参数指定

println()打印并且换行,在autoFlush为true时,会自动刷缓存

PrintStream用法和PrintWriter差不多,构造方法少一点

实例

publicstatic void main(String[] args) throws IOException {

// 打印流(只有输出流)PrintStream(字节打印流)  PrintWriter (字符打印流)

//               PrintStream ps = new PrintStream(newFileOutputStream("print.txt"));

PrintStream ps = newPrintStream("print.txt");

/*ps.print(true);

ps.print("中");

ps.print("f");*/

ps.print(18);    //编码

ps.write(97);    //字面值

ps.close();

}

1.5    数据流

DataOutputStream dos= //用数据流装饰文件流

newDataOutputStream(new FileOutputStream("g:/answer.txt"));

dos.writeInt(101);//向数据流中写100

dos.writeInt(100);

dos.writeInt(70);

dos.writeInt(66);

dos.close();//关闭处理会自动关闭所装饰的流

DataInputStream dis =new DataInputStream(

new FileInputStream("g:/answer.txt"));

int a=dis.readInt();//用数据流装饰文件流

System.out.println(a);

System.out.println(dis.readInt());//打印读出的int数据

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

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

dis.close();

DataOutputStream数据输出流,字节流、处理流

DataOutputStream(OutputStreamos)构造方法参数为它所装饰的字节输出流,添加了写基本类型数据的功能

writeInt(int i)

writeXXX(xxx i)

DataInputStream数据输入流

DataInputStream(InputStreamis)构造方法参数为它所装饰的字节输入流,添加了读基本数据类型的功能

int readInt()

xxx readXXX()

实例:

publicstatic void main(String[] args) throws IOException {

//数据流(过滤流)

FileOutputStream fos = newFileOutputStream("data.txt");

DataOutputStream oos = newDataOutputStream(fos);

oos.writeByte(100);

oos.writeChar('中');

oos.writeShort(1000);

oos.writeInt(1022);

oos.writeLong(12025);

oos.writeFloat(12.2f);

oos.writeDouble(15.4524);

oos.writeBoolean(true);

oos.close();

//读取数据

FileInputStream fis = new FileInputStream("data.txt");

DataInputStream dis = new DataInputStream(fis);

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

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

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

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

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

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

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

dis.close();

}

1.6    装饰模式

装饰模式:

1、把被装饰者通过构造方法传入装饰者

2、被装饰者和装饰者具有相同的方法(方法名、返回、参数)、具有相同的接口或父类

3、被装饰者以属性的形式存在于装饰者中

1.7    随机访问文件

RandomAccessFile raf= new RandomAccessFile("g:/answer.txt", "rw");

raf.write(65);//A|

raf.write(66);//AB|

raf.seek(0);//将游标一下子跳到第一个位置|AB

raf.write(67);

raf.write(68);

raf.close();

RandomAccessFile raf=new RandomAccessFile("g:/answer.txt", "r");

System.out.println(raf.read());

System.out.println(raf.read());

raf.seek(0);  //游标放到最前

System.out.println(raf.read());

System.out.println(raf.read());

raf.close();

RandomAccessFile随机访问文件,不是InputStream、OutputStream、Reader、Writer中的任一个子类

RandomAcceessFile(Stringpath,String mode)

构造方法第一个参数表示文件路径,第二个参数打开模式,如果是"rw"表示可读可写,如果是"r"表示只读

seek(int pos)定位,游标可以随便向前向后跳,只要不超出范围(Stream、Reader、Writer只能往后不能往前)

TAG标签: 韦德娱乐1946
版权声明:本文由韦德娱乐1946_韦德娱乐1946网页版|韦德国际1946官网发布于韦德娱乐1946网页版,转载请注明出处:Java中的IO框架流三,种类化流