IO


IO框架

什么是流?

概念:内存存储设备(硬盘)之间传输数据的通道

数据借助流传输。

 


流的分类

按流向:

  • 输入流:将【存储设备】中的数据内容读到【内存】中。

  • 输出流:将【内存】中的数据内容读到【存储设备】中。

按单位:

  • 字节流:以字节为单位,可以读写所有数据。

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

按功能:

  • 节点流:具有实际传输数据的读写功能。

  • 过滤流:再节点流的基础之上增强功能。

 


字节流

字节流的父类(抽象类):

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的使用:

 FileInputStream fis = new FileInputStream("D:\\a.txt");     --创建FileInputStream,并指定需要读取文件的路径
 fis.read();     --单个字节读取文件内容
 int data = 0;
 while((data = fis.read()) != -1){
     System.out.println((char)data);
 }
 fis.close();    --关闭
 ?
 ?
 FileInputStream fis = new FileInputStream("D:\\a.txt"); 
 byte[] buf = new byte[1024];    -- 一次性读取多个字节,使用数组进行缓冲
 int count = 0;
 while((count=fis.read(buf)) != -1){
     System.out.println(new String(buf,0,count));
 }

FileOutputStream的使用:

 FileOutputStream fos = new FileOutputStream("D:\\b.txt",true);      --创建FileOutputStream对象,指定输出文件的路径 当后面加上true时,则是在文件后面追加内容,而不是全部覆盖。
 fos.write(97);      --单个字节输出
 fos.write('b');
 fos.write('c');
 ?
 String string = "helloword";    --多个字节输出,调用getBytes()方法,转化为字节
 fos.write(string.getBytes());
 fos.close();

应用:文件复制

 FileInputStream fis = new FileInputStream("D:\\a.jpg");
 FileOutputStream fos = new FileOutputStream("D:\\b.jpg");
 byte[] buf = new byte[1024];
 int count = 0;
 while((count=fis.read(buf)) != -1){
     fos.write(buf,0,count);
 }
 fis.close();
 fos.close();

字节缓冲流

BufferedInputStream/BufferedOutputStream

  • 提高IO效率,减少访问磁盘的次数。

  • 数据存储在缓冲区中,flush是将缓冲区的内容写入文件中,也可以直接close。

 FileInputStream fis = new FileInputStream("D:\\a.jpg");
 BufferedInputStream bis = new BufferedInputStream(fis);
 int data = 0;
 while((data = bis.read()) != -1){
     System.out.print((char(data)));
 }
 bis.close();
 System.out.print("执行完毕!");
 FileOutputStream fos = new FileOutputStream("D:\\b.jpg");
 BufferedOutputStream bos = new BufferedOutputStream(fos);
 for(int i=0; i<10; i++){
     bos.write("helloword\r\n".getBytes());  --只是写入缓冲区,还没有写入文件
     bos.flush();    --刷新到硬盘
 }
 bos.close();

对象流

ObjectOutputStream/ObjectInputStream

  • 增强了缓冲区功能。

  • 增强了读写8种基本数据类型和字符串功能。

  • 增强了读写对象的功能。

    • readObject() --从流中读取一个对象

    • writeObject() --向流中写入一个对象

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

 

序列化

 使用ObjectOutputStream实现对象的序列化。
 注意点:序列化的对象必须要实现Serializable接口,否则会报异常
 ?
 1.创建对象流
 FileOutputStream fos = new FileOutputStream("D:\\stu.bin");
 ObjectOutputStream oos = new ObjectOutputStream(fos);
 2.序列化(写入操作)
 Student lihui = new Student("lihui",20);
 oos.writeObject(lihui);
 3.关闭
 oos.close();
 System.out.print("执行完毕!")
 ?
 public class Student implements Serializable{
 ?
 }

反序列化

 1.创建对象流
 FileInputStream fis = new FileInputStream("D:\\stu.bin");
 ObjectInputStream ois = new ObjectInputStream(fis);
 2.读取文件(反序列化)
 Student s = (Student)ois.readObject();
 3.关闭
 ois.close();
 System.out.println("执行完毕!");
 System.out.println(s.toString());

注意事项:

  • 序列化类必须要实现Serializable接口

  • 序列化类中对象属性要求实现Serializable接口(类属性里夹杂了其它类对象)。

  • 序列化版本号ID serialVersionUID,保证系列化的类和反序列化的类是同一个类。

  • 使用transient(瞬间的)修饰属性,这个属性不能被序列化。

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

  • 序列化多个对象,可以借助集合实现。

 


字符编码

ISO-8859-1:一般是美国使用,英文中一个字母代表一字节。中国字比较复杂,1字节=8位。

1字节(byte)=8位(bit)

1024字节=1K

1024k=1M

UTF-8:国际使用,基本上所有语言都包括。

GBK2312:简体中文。

GBK:简体中文,扩充。

当编码方式与解码方式不一致时,会出现乱码。

 


字符流

读取文件中的中文内容,中文并不是一个字代表一个字节,而是一个字代表多个字节,因此,使用字节流读取会出现乱码,要使用字符流。

字符流的父类(抽象类):

Reader:字符输入流

public int read(){}

public int read(char[] c){}

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

Writer:字符输出流

public void write(int n){}

public void write(String str){}

public void write(char[] c){}

文件字符流

  • FileReader:

    public int read(char[] c)

  • FileWriter:

    public void write(String str)

FileReader

 1.创建FileReader 文件字符输入流
 FileReader fr = new FileReader("D:\\hello.txt");
 2.读取
 char[] buf = new char[1024];
 int count = 0;
 while((count=fr.read(buf)) != -1){
     System.out.println(new String(buf,0,count));
 }
 3.关闭
 fr.close();

FileWriter

 1.创建FileWriter对象
 FileWriter fw = new FileWriter("D:\\hello.txt");
 2.写入
 for(int i=0; i<10; i++){
     fw.writer("java是世界上最好的语言!");
     fw.flush();
 }
 3.关闭
 fw.close();

应用:字符流复制文件

 1.创建写入写出对象
 FileReader fr = new FileReader("D:\\hello.txt");
 FileWriter fw = new FileWriter("D:\\hello1.txt");
 2.读写
 int data = 0;
 while((data=fr.read()) != -1){
     fw.write(data);
     fw.flush();
 }
 fr.close();
 fw.close();

注意:

  • 使用FileReader和FileWriter复制文本文件,不能复制图片或二进制文件(0101010....)。

  • 使用字节流可以复制任何形式文件。

 


字符缓冲流

BuffererReader\BufferedWrite

  • 高效读写

  • 支持输入换行符

  • 可一次写一行、读一行 readLine()

 1.创建缓冲流
 FileReader fr = new FileReader("D:\\hello.txt");
 BufferedReader br = new BufferedReader(fr);
 2.读取
 char[] buf = new char[1024];
 int count = 0;
 while((count = br.read()) != -1){
     System.out.print(new String(buf, 0, count));
 }
 3.关闭
 br.close();
 ?
 -- 也可以一行一行读取
 String line = null;
 while((line = br.readLine() != null)){
     System.out.println(line);
 }
 1.创建缓冲流
 FileWrite fw = new FileWrite("D:\\HELLO.txt");
 BufferedWrite bw = new BufferedWrite(fw);
 2.写入
 for(i =0; i<10; i++){
     bw.write("好好学习,天天向上!");
     bw.newLine();   --写入一个换行符
     bw.flush();
 }
 3.关闭
 bw.close();

 


打印流

PrintWrite()的使用:

  • 封装了prInt()/println()方法,支持写入后换行。

  • 支持数据原样打印。

 1.创建打印流
 PrintWrite pw = new PrintWrite("D:\\print.txt");
 2.打印
 pw.println(97);
 pw.println(true);
 pw.println('a');
 3.关闭
 pw.close();

 


转换流

桥转换流:InputStreamReader/OutputStreamWriter

  • 可将字节流转换为字符流

  • 设置字符的编码方式

 1.创建InputStreamReader对象
 FileInputStream fis = new FileInputStream("D:\\write.txt");
 InputStreamReader isr = new InputStreamReader(fis,"utf-8");     --带上编码方式
 2.读取文件
 int data = 0;
 while((data=isr.read()) != -1){
     System.out.println((char)data);
 }
 3.关闭
 isr.close();
 1.创建OutputStreamWrite
 FileOutputStream fos = new FileOutputStream("D:\\info.txt");
 OutputStreamWriter osw = new OutputStreamWriter(fos, "utf-8");
 2.写入
 for(int i =0; i<10; i++){
     osw.write("好好学习,天天向上!");
     osw.flush();
 }
 3.关闭
 osw.close();

 


File类

File类的使用:

  1. 分隔符。

  2. 文件操作。

  3. 文件夹操作。

 -- 分隔符
 public static void separator(){
     System.out.println("路径分隔符"+File.pathSeparator);     --路径分隔符 ;
     System.out.println("名称分隔符"+File.separator);         --名称分隔符 \
 }
 ?
 -- 文件操作
 public static void fileOpe(){
 ?
     1.创建文件
     File file = new File("d:\\file.txt");
     if(!file.exists){
         boolean b = file.createNewFile();
         System.out.println("创建结果" + b);
     }
     
     2.删除文件
     file.delete();
     
     3.获取文件信息
     System.out.println("获取文件的绝对路径" + file.getAbsolutePath());
     System.out.println("获取文件路径" + file.getPath());
     System.out.println("获取文件的名称" + file.getName());
     System.out.println("获取文件的父目录" + file.getParent());
     System.out.println("获取文件的长度" + file.getLength());
     System.out.println("获取文件的创建时间" + new Date(file.lastModified().toLocaleString());
     
     4.判断
     System.out.println("文件是否可写" + file.canWrite());
     System.out.println("是否是文件" + file.isFile());
     System.out.println("是否隐藏" + file.isHidden());
 }
 ?
 -- 文件夹的操作与文件的操作类似
 有一点需要注意
 dir.mkdir();    --只能创建单级目录
 dir.mkdirs();   --可以创建多级目录

 


Properties

Map接口中还有一个实现类Hashtable,它和HashMap 十分相似,区别在于Hashtable是线程安全的。Hashtable存取元素时速度很慢,目前基本上被HashMap类所取代,但Hashtable类有一个子类Properties在实际应用中非常重要,Properties主要用来存储字符串类型的键和值,在实际开发中,经常使用Properties集合来存取应用的配置项。

  • Properties:属性集合。

  • 特点:

    • 存储属性名和属性值

    • 属性名和属性值都是字符串类型

    • 没有泛型

    • 和流有关 可保存在流中或从流中加载

 

 1.创建集合
 Properties properties = new Properties();
 2.添加数据
 properties.setProperties("username", "lihui");
 properties.setProperties("age", "20");
 3.遍历
 Set pronames = properties.stringPropertyNames();
 for(String pro : pronames){
     System.out.println(pro + "-----------" + propeoties.getProperties(pro)); 
 }
 ?
 -- 和流有关的方法
 -- list 方法
 PrintWriter pw = new PrintWriter("D:\\print.txt");
 properties.list(pw);
 pw.close();
 ?
 -- store方法 保存
 FileOutputStream fos = new FileOutputStream("D:\\store.properties");
 properties.store(fos);
 fos.close();
 ?
 -- load方法 加载
 FileInputStream fis = new FileInputStream("D:\\store.properties");
 properties.load(fis);
 fis.close(); 

 

总结:

流的概念:

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

流的分类:

  • 输入流,输出流;字节流,字符流;节点流,功能流。

序列化、反序列化:

  • 将对象通过流写入到文件,或将对象通过流读取到内存,必须实现Serializable。

File对象:

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

相关