9-io基础

学习图灵基础课以及王争专栏总结

一、File类

File是io操作磁盘文件以及文件目录的一个核心类。虽然名字是文件,但是本质是文件/目录。

在最初学习io时,我老以为io就是操作文件或者目录的。但是后面发现这只是其中的一个类别,io可以是文件,网络,内存,管道,标准输入输出等。

1)常用方法

方法名

描述

createNewFile()

创建一个文件

mkdir()

创建一个目录,只能创建一级

mkdirs()

创建一个多级目录,如 aaa/bbb/ccc, 同时创建

isFile()

判断是否是文件

isDirectory()

判断是否是目录

delete()

删除文件或空目录

exists()

是否存在

getName()

获得文件名字,只有名称,没有路径

getPath()

获得路径,也会有名称

getAbsolutePath()

获得绝对路径

getParent()

获得父类File的名称

getParentFile()

获得父类File

list()

获得目录下所有文件/目录的名称(只获得该目录下级,不会有下下级)

listFiles()

获得目录下所有文件/目录。

length()

获得文件的长度。

separator()

路径的隔开符

2)FileFilter接口/FilenameFilter接口:

File.list() 与FilenameFilter配合 ,File.listFiles()可以配合FileFilter/FilenameFilter接口使用。

重写FileFilter里的public boolean accept(File pathname)方法。

用法如下:

File[] files = file.listFiles(new FileFilter() {
    @Override
    public boolean accept(File pathname) {
        if(pathname.isDirectory() || pathname.getName().endsWith("txt")){
            return true;
        }
        return false;
    }
});

FilenameFilter类似

二、各系统的路径问题

引用自:java 路径中 /与\\ linux系统的路径_linux服务器上java后台项目的上传文件路径是/还是\\-优快云博客

1)windows下的路径

在windows下路径一般为:D:\\demo\\text.txt

2)Linux下的路径

在linux下路径一般为:/usr/local/txt.txt。

3)通用用法

windows下的写法\\ 在linux下无法被识别,但是linux的 / 在windows下也可以被识别。所以可以用\来隔开。

还有File.separator()。这个更专业,在所有系统下通用。

如:

File.separator()+"demo"+File.separator()+"txt.txt"这样。

三、IO概述

io的中文名是输入/输入,英文为input/output。在计算机中,常用的io设备有磁盘,键盘,网络,显示器等,在操作系统层面有文件,网络,标准输入输出(对应键盘,显示器),管道等,而io就是来读写这些设备的。java有java.io和java.nio两套类库。

java.io是jdk1.4版本就有的,java.nio则是jdk1.4版本加入的。nio支持非阻塞io的开发,在jdk1.7中对nio类库进行了升级,支持异步非阻塞io的开发。

四、IO分类概述

根据数据的流向分为:输入流输出流

输入流 :把数据从其他设备上读取到内存的流。

输出流 :把数据从内存中写出到其他设备上的流。

根据数据的类型分为:字节流字符流

字节流 :以字节为单位,读写数据的流。

字符流 :以字符为单位,读写数据的流。

输入流

输出流

字节流

字节输入流

InputStream

字节输出流

OutputStream

字符流

字符输入流

Reader

字符输出流

Writer

五、基础类用法

1)字节流

字节流的意思很明显,就是以数库类型为byte的流,而计算机系统底层都是以二进制进行存储的,那么字节流可以传输任意文件。

字节输出流

java.io.OutputStream是所有字节输出流的超类。其主要方法为

public void close() :关闭此输出流并释放与此流相关联的任何系统资源。

public void flush() :刷新此输出流并强制任何缓冲的输出字节被写出。

public void write(byte[] b):将 b.length字节从指定的字节数组写入此输出流。

public void write(byte[] b, int off, int len) :从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。

public abstract void write(int b) :将指定的字节输出流。

FileOutputStream类

构造方法:

public FileOutputStream(File file):创建文件输出流以写入由指定的 File对象表示的文件。

public FileOutputStream(File file, boolean append)

public FileOutputStream(String name): 创建文件输出流以指定的名称写入文件。

public FileOutputStream(String name, boolean append) 注意这个,默认append为false,每次输出都会覆盖文件,当为true时不会覆盖而是往后添加。

1、写出字节:write(int b) 方法,每次可以写出一个字节数据

2、写出字节数组:write(byte[] b),每次可以写出数组中的数据

3、写出指定长度字节数组:write(byte[] b, int off, int len) ,每次写出从off索引开始,len个字节

示例:

        // 使用File对象创建流对象
        File file = new File("a.txt");
        FileOutputStream fos = new FileOutputStream(file);
      
        // 使用文件名称创建流对象
        FileOutputStream fos = new FileOutputStream("b.txt");
        
        // 使用文件名称创建流对象
        FileOutputStream fos = new FileOutputStream("fos.txt");     
      	// 写出数据:虽然参数为int类型四个字节,但是只会保留一个字节的信息写出
      	fos.write(97); // 写出第1个字节
      	fos.write(98); // 写出第2个字节
      	fos.write(99); // 写出第3个字节
      	// 关闭资源
        fos.close();
        
        // 使用文件名称创建流对象
        FileOutputStream fos = new FileOutputStream("fos.txt");     
      	// 字符串转换为字节数组
      	byte[] b = "你好中国".getBytes();
      	// 写出字节数组数据
      	fos.write(b);
      	// 关闭资源
        fos.close();
        
        // 使用文件名称创建流对象
        FileOutputStream fos = new FileOutputStream("fos.txt");     
      	// 字符串转换为字节数组
      	byte[] b = "abcde".getBytes();
		// 写出从索引2开始,2个字节。索引2是c,两个字节,也就是cd。
        fos.write(b,2,2);
      	// 关闭资源
        fos.close();	

字节输入流

java.io.InputStream是所有输入流的超类,其主要方法为

public void close() :关闭此输入流并释放与此流相关联的任何系统资源。

public abstract int read(): 从输入流读取数据的下一个字节。

public int read(byte[] b): 从输入流中读取一些字节数,并将它们存储到字节数组 b中 。

public int available(); 返回输入流中字节的长度。

FileInputStream类

构造方法:

FileInputStream(File file): 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的 File对象 file命名。

FileInputStream(String name): 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的路径名 name命名。

1、读取字节:read方法,每次可以读取一个字节的数据,提升为int类型,读取到文件末尾,返回-1

2、使用字节数组读取:read(byte[] b),每次读取b的长度个字节到数组中,返回读取到的有效字节个数,读取到末尾时,返回-1

示例:

	// 使用File对象创建流对象
        File file = new File("a.txt");
        FileInputStream fos = new FileInputStream(file);
      
        // 使用文件名称创建流对象
        FileInputStream fos = new FileInputStream("b.txt");
        
        // 使用文件名称创建流对象
       FileInputStream fis = new FileInputStream("read.txt");
        // 读取数据,返回一个字节
        int read = fis.read();
        System.out.println((char) read);
        read = fis.read();
        System.out.println((char) read);
        read = fis.read();
        System.out.println((char) read);
        read = fis.read();
        System.out.println((char) read);
        read = fis.read();
        System.out.println((char) read);
      	// 读取到末尾,返回-1
       	read = fis.read();
        System.out.println( read);
		// 关闭资源
        fis.close();
        
        // 使用文件名称创建流对象
       FileInputStream fis = new FileInputStream("read.txt");
      	// 定义变量,保存数据
        int b ;
        // 循环读取
        while ((b = fis.read())!=-1) {
            System.out.println((char)b);
        }
		// 关闭资源
        fis.close();
        
        // 使用文件名称创建流对象.
       FileInputStream fis = new FileInputStream("read.txt"); // 文件中为abcde
      	// 定义变量,作为有效个数
        int len ;
        // 定义字节数组,作为装字节数据的容器   
        byte[] b = new byte[2];
        // 循环读取
        while (( len= fis.read(b))!=-1) {
           	// 每次读取后,把数组的有效字节部分,变成字符串打印
            System.out.println(new String(b,0,len));//  len 每次读取的有效字节个数
        }
        //也可以  byte[] c = new byte[fis.available];  就可以一次全读取了,字符流没有这个
		// 关闭资源
        fis.close();
        

2)字符流

字符流以字符为数据类型传输的流,字符流需要注意字符编码的问题

字符输入流

java.io.Reader抽象类是表示用于读取字符流的所有类的超类,可以读取字符信息到内存中。它定义了字符输入流的基本共性功能方法。

public void close() :关闭此流并释放与此流相关联的任何系统资源。

public int read(): 从输入流读取一个字符。

public int read(char[] cbuf): 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中 。

FileReader类

构造方法

  • FileReader(File file): 创建一个新的 FileReader ,给定要读取的File对象。
  • FileReader(String fileName): 创建一个新的 FileReader ,给定要读取的文件的名称。

构造时使用系统默认的字符编码和默认字节缓冲区。

  1. 字符编码:字节与字符的对应规则。Windows系统的中文编码默认是GBK编码表。
    idea中UTF-8
  2. 字节缓冲区:一个字节数组,用来临时存储字节数据。

1、读取字符read方法,每次可以读取一个字符的数据,提升为int类型,读取到文件末尾,返回-1,循环读取

2、使用字符数组读取read(char[] cbuf),每次读取b的长度个字符到数组中,返回读取到的有效字符个数,读取到末尾时,返回-1

示例:

// 使用File对象创建流对象
        File file = new File("a.txt");
        FileReader fr = new FileReader(file);
      
        // 使用文件名称创建流对象
        FileReader fr = new FileReader("b.txt");

// 使用文件名称创建流对象
       	FileReader fr = new FileReader("read.txt");
      	// 定义变量,保存有效字符个数
        int len ;
        // 定义字符数组,作为装字符数据的容器
        char[] cbuf = new char[2];
        // 循环读取
        while ((len = fr.read(cbuf))!=-1) {
            System.out.println(new String(cbuf,0,len));
        }
    	// 关闭资源
        fr.close();

字符输出流

java.io.Writer抽象类是表示用于写出字符流的所有类的超类,将指定的字符信息写出到目的地。它定义了字符输出流的基本共性功能方法。

  • void write(int c) 写入单个字符。
  • void write(char[] cbuf)写入字符数组。
  • abstract void write(char[] cbuf, int off, int len)写入字符数组的某一部分,off数组的开始索引,len写的字符个数。
  • void write(String str)写入字符串。
  • void write(String str, int off, int len) 写入字符串的某一部分,off字符串的开始索引,len写的字符个数。
  • void flush()刷新该流的缓冲。
  • void close() 关闭此流,但要先刷新它。

FileWriter类
  • FileWriter(File file): 创建一个新的 FileWriter,给定要读取的File对象。
  • FileWriter(String fileName): 创建一个新的 FileWriter,给定要读取的文件的名称。
  • FileWriter(String fileName, boolean append)同字节流,默认覆盖,true时为添加

构造时使用系统默认的字符编码和默认字节缓冲区。

1、写出字符write(int b) 方法,每次可以写出一个字符数据

2、写出字符数组write(char[] cbuf)write(char[] cbuf, int off, int len) ,每次可以写出字符数组中的数据,用法类似FileOutputStream

3、写出字符串write(String str)write(String str, int off, int len) ,每次可以写出字符串中的数据,更为方便

因为内置缓冲区的原因,如果不关闭输出流,无法写出字符到文件中。但是关闭的流对象,是无法继续写出数据的。如果我们既想写出数据,又想继续使用流,就需要flush 方法了。

示例:

// 使用File对象创建流对象
        File file = new File("fw.txt");
        FileWriter fw = new FileWriter(file);
      
        // 使用文件名称创建流对象
        FileWriter fw = new FileWriter("fw.txt");

  // 使用文件名称创建流对象
        FileWriter fw = new FileWriter("fw.txt");     
      	// 写出数据
      	fw.write(97); // 写出第1个字符
      	fw.write('b'); // 写出第2个字符
      	fw.write('C'); // 写出第3个字符
      	fw.write(30000); // 写出第4个字符,中文编码表中30000对应一个汉字。
      
      	/*
        【注意】关闭资源时,与FileOutputStream不同。
      	 如果不关闭,数据只是保存到缓冲区,并未保存到文件。
        */
        // fw.close();

 // 使用文件名称创建流对象
        FileWriter fw = new FileWriter("fw.txt");
        // 写出数据,通过flush
        fw.write('刷'); // 写出第1个字符
        fw.flush();
        fw.write('新'); // 继续写出第2个字符,写出成功
        fw.flush();
      
      	// 写出数据,通过close
        fw.write('关'); // 写出第1个字符
        fw.close();
        fw.write('闭'); // 继续写出第2个字符,【报错】java.io.IOException: Stream closed
        fw.close();


  // 使用文件名称创建流对象
        FileWriter fw = new FileWriter("fw.txt");     
      	// 字符串转换为字节数组
      	char[] chars = "你好中国".toCharArray();
      
      	// 写出字符数组
      	fw.write(chars); 
        
		// 写出从索引2开始,2个字节。索引2是'中',两个字节,也就是'中国'。
        fw.write(b,2,2); //中国
      
      	// 关闭资源
        fos.close();

// 使用文件名称创建流对象
        FileWriter fw = new FileWriter("fw.txt");     
      	// 字符串
      	String msg = "你好中国";
      
      	// 写出字符数组
      	fw.write(msg); //你好中国
      
		// 写出从索引2开始,2个字节。索引2是'中',两个字节,也就是'中国'。
        fw.write(msg,2,2);	// 中国
      	
        // 关闭资源
        fos.close();

3)缓冲流

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

  • 字节缓冲流BufferedInputStreamBufferedOutputStream
  • 字符缓冲流BufferedReaderBufferedWriter

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

如果每次读写是大于或等于8kb即8192字节,那么缓冲流不会有性能上的优势,甚至会更慢。

另外缓冲流的输出文件是否拼接,由里面的OutputStream, Writer决定。

字节缓冲流

构造方法:

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

示例:

// 创建字节缓冲输入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("bis.txt"));
// 创建字节缓冲输出流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("bos.txt"));

字符缓冲流

构造方法

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

示例:

// 创建字符缓冲输入流
BufferedReader br = new BufferedReader(new FileReader("br.txt"));
// 创建字符缓冲输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt"));

特有方法

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

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

示例1:

 // 创建流对象
        BufferedReader br = new BufferedReader(new FileReader("in.txt"));
		// 定义字符串,保存读取的一行文字
        String line  = null;
      	// 循环读取,读取到最后返回null
        while ((line = br.readLine())!=null) {
            System.out.print(line);
            System.out.println("------");
        }
		// 释放资源
        br.close();

示例2:

// 创建流对象
		BufferedWriter bw = new BufferedWriter(new FileWriter("out.txt"));
      	// 写出数据
        bw.write("hello");
      	// 写出换行
        bw.newLine();
        bw.write("world");
        bw.newLine();
        bw.write("!");
        bw.newLine();
		// 释放资源
        bw.close();

4)转换流

在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();
    }
}
输出结果:
���

那么如何读取GBK编码的文件呢?

InputStreamReader类

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

构造方法

  • InputStreamReader(InputStream in): 创建一个使用默认字符集的字符流。
  • InputStreamReader(InputStream in, String charsetName): 创建一个指定字符集的字符流。

示例:

// 定义文件路径,文件为gbk编码
        String FileName = "E:\\file_gbk.txt";
      	// 创建流对象,默认UTF8编码
        InputStreamReader isr = new InputStreamReader(new FileInputStream(FileName));
      	// 创建流对象,指定GBK编码
        InputStreamReader isr2 = new InputStreamReader(new FileInputStream(FileName) , "GBK");
		// 定义变量,保存字符
        int read;
      	// 使用默认编码字符流读取,乱码
        while ((read = isr.read()) != -1) {
            System.out.print((char)read); // ��Һ�
        }
        isr.close();
      
      	// 使用指定编码字符流读取,正常解析
        while ((read = isr2.read()) != -1) {
            System.out.print((char)read);// 大家好
        }
        isr2.close();
OutputStreamWriter类

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

构造方法

  • OutputStreamWriter(OutputStream in): 创建一个使用默认字符集的字符流。
  • OutputStreamWriter(OutputStream in, String charsetName): 创建一个指定字符集的字符流。

示例:

// 定义文件路径
        String FileName = "out.txt";
      	// 创建流对象,默认UTF8编码
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(FileName));
        // 写出数据
      	osw.write("你好"); // 保存为6个字节
        osw.close();
      	
		// 定义文件路径
		String FileName2 = "out2.txt";
     	// 创建流对象,指定GBK编码
        OutputStreamWriter osw2 = new OutputStreamWriter(new FileOutputStream(FileName2),"GBK");
        // 写出数据
      	osw2.write("你好");// 保存为4个字节
        osw2.close();

StandardCharsets 标准的字符编码常量类。

5)序列化

https://blog.51cto.com/u_16175463/8684056 序列化的serialVersionUID

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

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

ObjectOutputStream类

java.io.ObjectOutputStream 类,将Java对象的原始数据类型写出到文件,实现对象的持久存储。

序列化操作

一个对象要想序列化,必须满足两个条件:

  • 必须实现Serializable接口。
  • 必须保证其所有属性均可序列化。(transient修饰为临时属性,不参与序列化)

写出对象方法

  • public final void writeObject (Object obj) : 将指定的对象写出。

示例:

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);
    }
}
public class SerializeDemo{
   	public static void main(String [] args)   {
    	Employee e = new Employee();
    	e.name = "zhangsan";
    	e.address = "guangzhou";
    	e.age = 20; 
    	try {
      		// 创建序列化流对象
          ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("employee.txt"));
        	// 写出对象
        	out.writeObject(e);
        	// 释放资源
        	out.close();
        	fileOut.close();
        	System.out.println("序列化完成"); // 姓名,地址被序列化,年龄没有被序列化。
        } catch(IOException i)   {
            i.printStackTrace();
        }
   	}
}
ObjectInputStream类

ObjectInputStream反序列化流,将之前使用ObjectOutputStream序列化的原始数据恢复为对象。

反序列化操作

如果能找到一个对象的class文件,我们可以进行反序列化操作,调用ObjectInputStream读取对象的方法,

public final Object readObject () : 读取一个对象。

示例:

public class DeserializeDemo {
   public static void main(String [] args)   {
        Employee e = null;
        try {		
             // 创建反序列化流
             FileInputStream fileIn = new FileInputStream("employee.txt");
             ObjectInputStream in = new ObjectInputStream(fileIn);
             // 读取一个对象
             e = (Employee) in.readObject();
             // 释放资源
             in.close();
             fileIn.close();
        }catch(IOException i) {
             // 捕获其他异常
             i.printStackTrace();
             return;
        }catch(ClassNotFoundException c)  {
        	// 捕获类找不到异常
             System.out.println("Employee class not found");
             c.printStackTrace();
             return;
        }
        // 无异常,直接打印输出
        System.out.println("Name: " + e.name);	// zhangsan
        System.out.println("Address: " + e.address); // beiqinglu
        System.out.println("age: " + e.age); // 0
    }
}

注意:

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

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

发生这个异常的原因,该类的序列版本号与从流中读取的类描述符的版本号不匹配 ,serialVersionUID 该版本号的目的在于验证序列化的对象和对应类是否版本匹配。

serialVersionUID是一个非常重要的字段,因为 Java 的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM 会把传来的字节流中的serialVersionUID与本地相应实体(类)的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。

一般来说,定义serialVersionUID的方式有两种,分别为:

采用默认的1L,具体为private static final long serialVersionUID = 1L;

在可兼容的前提下,可以保留旧版本号,如果不兼容,或者想让它不兼容,就手工递增版本号。

1->2->3.....

根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段,例如 private static final long serialVersionUID = XXXL;

这种方式适用于这样的场景:

开发者认为每次修改类后就需要生成新的版本号,不想向下兼容,操作就是删除原有serialVesionUid声明语句,再自动生成一下。

第二种能够保证每次更改类结构后改变版本号,但还是要手工去生成

示例:

public class Employee implements java.io.Serializable {
     // 加入序列版本号
     private static final long serialVersionUID = 1L;
     public String name;
     public String address;
     // 添加新的属性 ,重新编译, 可以反序列化,该属性赋为默认值.
     public int eid; 

     public void addressCheck() {
         System.out.println("Address  check : " + name + " -- " + address);
     }
}

6)Properties属性类

常用方法

  • public Object setProperty(String key, String value) : 保存一对属性。
  • public String getProperty(String key) :使用此属性列表中指定的键搜索属性值。
  • public Set<String> stringPropertyNames() :所有键的名称的集合。
  • public void load(InputStream inStream): 从字节输入流中读取键值对。

示例1:

 // 创建属性集对象
        Properties properties = new Properties();
        // 添加键值对元素
        properties.setProperty("filename", "a.txt");
        properties.setProperty("length", "123");
        properties.setProperty("location", "D:\\a.txt");
        // 打印属性集对象
        System.out.println(properties);
        // 通过键,获取属性值
        System.out.println(properties.getProperty("filename"));
        System.out.println(properties.getProperty("length"));
        System.out.println(properties.getProperty("location"));

        // 遍历属性集,获取所有键的集合
        Set<String> strings = properties.stringPropertyNames();
        // 打印键值对
        for (String key : strings ) {
          	System.out.println(key+" -- "+properties.getProperty(key));
        }

示例2:

 // 创建属性集对象
        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));
        }

六、按装饰类与原装类进行区分

除了根据数据的流向,以及数据的类型进行区分,还可以按以下方式用装饰器类和原装类进行区分。

1)原始类:

文件类:

字节流:FileInputStream, FileOutPutStream

字符流:FileReader, FileWriter

网络:

io没有专门用于网络的类,一般配合java.net类库,直接使用InputStream,OutputStream进行读写。

内存:

字节流:ByteArrayInputStream,ByteArrayOutputStream

字符流:CharArrayReader,CharArrayWriter

在做单元测试,或者处理第三方的流时,可以直接将其转换成上面的,没必要再封装成文件或什么来操作。

PipedOutputStream out = new PipedOutputStream();
PipedInputStream in = new PipedInputStream(out);
new Thread(new Runnable() {
 @Override
 public void run() {
   try {
     out.write("Hi wangzheng~".getBytes());
   } catch (IOException e) {
     e.printStackTrace();
   }
 }
}).start();

new Thread(new Runnable() {
 @Override
 public void run() {
   byte[] buffer = new byte[512];
   try {
     in.read(buffer);
     System.out.println(new String(buffer));
   } catch (IOException e) {
     e.printStackTrace();
   }
 }
}).start();

管道

字节流:PipedInputStream、PipedOutputStream、

字符流:PipedReader、PipedWriter

管道是Java提供的为同一个进程内两个线程之间通信的工具,一个线程通过PipedOutputStream写入的数据,另一个线程就可以通过PipedInputStream读取数据,示例代码如下所示

标准输入输出

在操作系统中,一般会有三个标准I/O系统:标准输入、标准输出、标准错误输出。标准输入对应I/O设备中的键盘,标准输出和标准错误输出对应I/O设备中的屏幕。Java中的标准输入为System.in,它是一个定义在System类中的静态InputStream对象。Java中的标准输出和标准错误输出分别为System.out和System.err,它们都是定义在System类中的PrintStream对象。PrintStream为装饰器类,需要嵌套OutputStream来使用,支持按照格式输出数据,System.in、System.out、System.err的使用示例如下所示。

Scanner s = new Scanner(System.in);
System.out.println("echo: " + s.nextLine());
//System.err显示的字符串为红色,以表示出错
System.err.println("echo: " + s.nextLine());

2)装饰器类

装饰器类一般用于对原始类的增强

支持读写缓存功能的装饰器类

BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter

上面基础类用法已经说过

支持基本类型数据读写的装饰器类

DataInputStream支持将从输入流中读取的数据解析为基本类型(byte、char、short、int、float、double等),DataOutputStream类支持将基本类型数据转化为字节数组写入输出流。示例代码如下所示。

DataOutputStream out = new DataOutputStream(new FileOutputStream("/Users/wangzheng/a.txt"));
out.writeInt(12);
out.writeChar('a');
out.writeFloat(12.12f);
out.close();

DataInputStream in = new DataInputStream(new FileInputStream("/Users/wangzheng/a.txt"));
System.out.println(in.readInt());
System.out.println(in.readChar());
System.out.println(in.readFloat());
in.close();

调用DataOutputStream的readChar()、writeChar()函数,我们也可以按字符为单位读取、写入数据,但跟字符流类不同的地方是,DataOutputStream类一次只能处理一个字符,而字符流类可以处理char数组,并且字符流类提供的函数更多,功能更加丰富。

支持对象读写的装饰器类

即上面的序列化ObjectInputStream和ObjectOutputStream.

支持格式化打印数据的装饰器类

PrintStream和PrintWriter可以将数据按照一定的格式,转化为字符串,写入到输出流。前面讲到System.out、System.err就是PrintStream类型的。示例代码如下所示。

PrintStream printStream =new PrintStream(new FileOutputStream("/Users/wangzheng/a.txt"));
printStream.print(124); //int->Integer->toString(), 写入字符串"124"
printStream.printf("hello %d", 43); //写入字符串"hello 43"

特殊的装饰器类

即上面的转换流

正常应该是字节流原始类对字节流的装饰器类,字符流对字符流的装饰器类

而此处字符流的装饰器类,用了字节流的原始类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值