java标准的IO操作

使用java IO我们可以对外界设备以相同的方式进行读写,完成数据交换

同一套操作,来操作不同的设备

java IO将"读"与"写"按照方向进行了划分:

输入:从外界到程序的方向,用于让程序获取外界数据
因此输入是"读"数据的操作

输出:从程序到外界的方向,用于将数据"写"出的操作.

输入流(InputStream)、输出流(OutputStream),流动的是字节流

java IO以"流"的形式表示读写功能

InputStream是所有字节输入流的父类,其定义了基础的读取方法

通过输入流我们可以连接上外界设备从而读取该设备数据

常用的方法如下:

  • int read()
    读取一个字节,以int形式返回,该int值的"低八位”有效,若返回值为-1则表示EOF
  • int read(byte[] d)
    尝试最多读取给定数组的length个字节并存入该数组,返回值为实际读取到的字节量。

OutputStream是所有字节输出流的父类,其定义了基础的写出方法

常用的方法如下:

  • void write(int d)
    写出一个字节写的是给定的in的”低八位”
  • void write(byte[ d)
    将给定的字节数组中的所有字节全部写出

节点流(低级流)与处理流(高级流)

java将流分为两大类:节点流与处理流

按照流是否直接与特定的地方(如磁盘、内存、设备等)相连,分为节点流和处理流两类。

节点流:也称为低级流

可以从或向一一个特定的地方(节点)读写数据。

真实连接程序与数据源的"管道",用于实际搬运数据的流
读写一定是建立在节点流的基础上进行的

处理流:又称为“高级流”或“过滤流”

是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。

高级流不能独立存在,必须连接在其他流上,目的是当数据 流经当前流时对其做某些加工处理,简化我们读写数据时的相应操作

可以理解为:处理水的热水器、净水器,单独存在无意义,连接在其他流上(低级流和高级流)才有用

流的链接:
处理流的构造方法总是要带一个其他的流对象做参数,一个流对象经过其他流的多次包装,称为流的链接。
换种说法
实际使用IO时,我们通常会串联若干的高级流最终连接到低级流上,使得读写数据以流水线式加工处理完成,这个操作称为“流的连接”,这也是IO的精髓所在

相当于把热水器或净水器连接到水管上(高级流连低级流)
把热水器连接到净水器上(高级流连高级流)
流动的是数据

这种设计模式是装饰者模式
在不改变原有类的情况下,增强其能力

文件流(一种低级流)

文件流是一对低级流,作用是连接到文件上,用于读写文件数据
java.io.FileOutputStream:文件输出流
java.io.FileInputStream:文件输入流

文件流提供的构造方法:

FileOutputStream(File file)
FileOutputStream(String path)
以上两种创建方式,默认为覆盖写模式
即:若指定的文件已经存在,那么会将该文件原有数据全部删除,然后再将新数据写入文件

FileOutputStream(File file,boolean append)
FileOutputStream(String path,boolean append)
以上两种构造器允许再传入一个boolean值类型的参数,
如果该值为true时,文件输出流就是追加写模式
即:数据中原有数据都保留,新内容会被追加到文件末尾

文件输出流:

package io;import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;public class FosDemo {public static void main(String[] args) throws UnsupportedEncodingException, IOException {FileOutputStream fos = new FileOutputStream("./fos.txt",true);//String line = "回首,掏~";//fos.write(line.getBytes("UTF-8"));//fos.write("鬼刀一开看不见~走位~走位~".getBytes("UTF-8"));fos.write("手".getBytes("UTF-8"));System.out.println("写出完毕!");fos.close();}
}

文件输入流:

package io;import java.io.FileInputStream;
import java.io.IOException;public class FISDemo {public static void main(String[] args) throws IOException {FileInputStream fis = new FileInputStream("fos.txt");byte[] data = new byte[1000];  //提供读取的容器int len = fis.read(data); //记录读取的实际长度//String str = new String(data,"utf-8").trim();//String 还支持另外一种重载(字节数组,起始下标,结束下标,编码格式)String str = new String(data,0,len,"utf-8");System.out.println(str);fis.close();}
}

文件流与RAF的区别:

RAF是基于指针的随机读写形式
可以对文件任意位置进行读或写的操作,可以做到对文件部分数据覆盖等操作,读写更灵活。

文件流是基于java IO的标准读写,而IO是顺序读写模式
即:只能向后写或读数据,不能回退,没有指针

单从读写灵活度来讲RAF是优于文件流的
但是文件流可以基于java IO的流连接完成一个复杂数据的读写
这是RAF做不到的,选择这两种方法时,根据实际需求不用过于纠结

练习:使用文件流完成文件的复制工具

package io;import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;/*** 使用文件流完成文件的复制工具* @author Tian**/
public class CopyDemo {public static void main(String[] args) throws IOException {//创建存取数据的字节数组(数据容器,相当于交换变量值时的第三方变量)byte[] data = new byte[1024*10];//记录运行开始时间long start = System.currentTimeMillis();//读取源文件,创建输入流(注意输入是从文件输入到现在的这个代码程序)FileInputStream fis = new FileInputStream("./image.jpg");//写入复制文件,创建输出流(注意输出是从现在这个程序写出到文件)FileOutputStream fos = new FileOutputStream("./image_copy.jpg");int len = -1; //记录读取的实际长度//循环写入每次的10k大小字节数组while((len = fis.read(data))!=-1){//读取信息并返回读取长度存储到len中//将字节数组的信息写入复制的文件fos.write(data,0,len);}//读取完毕,关闭输入流fis.close();//写出完毕,关闭输出流fos.close();//记录运行结束时间long end = System.currentTimeMillis();//程序运行结束,输出时间System.out.println("复制完毕,耗时:"+(end-start)/1000+"s");}
}

常见的高级流(加工数据的工具)

一、缓冲流(在流连接中的提高速读写效率)

java.io.BufferedOutputStream
java.io.BufferedInputStream

缓冲流是一对高级流,在流连接中的作用是提高速读写效率
使得我们在进行读写操作时用单字节读写也能提高读写的效率

在向硬件设备做写出操作时,增大写出次数无疑会降低写出效率
为此我们可以使用缓冲输出流来一 次性批量写出若干数据,减少写出次数来提高写出效率

BufferedOutputStream缓冲输出流内部维护着一个缓冲区(一个8k字节数组)
每当我们向该流写数据时,都会先将数据存入缓冲区
当缓冲区已满时,缓冲流会将数据一次性全部写出

无论我们使用缓冲流进行何种读写(单字节或块读写),最终都会被缓冲流转换为块读写,来提高效率

package io;import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;public class CopyDemo2 {public static void main(String[] args) throws IOException {//创建输入流FileInputStream fis = new FileInputStream("./image.jpg");//创建输入流的缓冲流,传入参数为输入流BufferedInputStream bis= new BufferedInputStream(fis); //创建输出流FileOutputStream fos = new FileOutputStream("./image_copy.jpg");//创建输出流的缓冲流,传入参数为输出流BufferedOutputStream bos = new BufferedOutputStream(fos);//复制时,一次一字节int d = -1;//对缓冲流进行操作就行了while((d = bis.read())!=-1){bos.write(d);}//关闭时,关闭缓冲流会自动关闭其附身的低级流bis.close();bos.close();}
}

缓冲输出流的缓冲区问题:

使用缓冲输出流可以提高写出效率,但是这也存在着一个问题,就是写出数据缺乏即时性。
有时我们需要在执行完某些写出操作后,就希望将这些数据确实写出
而非在缓冲区中保存直到缓冲区满后才写出
这时我们可以使用缓冲流的一个方法flush

void flush() 清空缓冲区,将缓冲区中的数据强制写出
flush方法是OutputStream中定义的方法
所有的输出流都具有该方法,但是只有缓冲流的该方法实现了,有实际意义
其他的流具有该方法的目的是在流连接中传递缓冲操作给缓冲流

flush的作用是将缓冲流中已经缓存的数据一次性写出
频繁的调用flush方法会提高写出次数从而降低写出效率,但是能保证数据写出的及时性
所以需要根据实际需求选择,比如文件复制不用,但是聊天需要用flush

package io;import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;public class BOS_flush {public static void main(String[] args) throws UnsupportedEncodingException, IOException {FileOutputStream fos = new FileOutputStream("./bos.txt");BufferedOutputStream bos = new BufferedOutputStream(fos);bos.write("此剑抚平天下不平事,此剑无愧世间有愧人".getBytes("utf-8"));bos.flush();System.out.println("写出完毕!");//close时也会自动调用flush,class方法中调用了flush方法bos.close();}
}

二、对象流(在流连接中读写java对象)

java.io.ObjectOutputStream
java.io.ObjectInputStream

对象流是一种高级流,在流连接中的作用是方便读写java对象(对象与字节的转换由对象流完成)
将java对象按照其结构,转换成字节流,存入文件

对象流的三大块:类的创建、类对象的写入(对象输出流)、类对象的读出(对象输入流)

1、对象流中访问类的创建

使用当前类的实例测试对象流的对象读写操作时

注意:使用对象流的类如果报java.io.NotSerializableException

说明该类要实现Serializable的接口,该接口为序列化操作

ps:
序列化:把一组数据按一个结构转化为一组字节信息的过程
Serializable:是签名接口,我们开发一般不用,这种接口一般是java做的
签名接口:没有方法内容,在编译时,编译器为自动添加方法,即:在java文件编译成class文件后才会出现

签名接口:没有方法内容,在编译时,编译器为自动添加方法,即:在java文件编译成class文件后才会出现

在实现序列化接口后,该类会提示添加一个序列化版本号
**序列化版本号:**java会默认指定加上,这个会影响反序列化,写出与读入的版本号要一致,否则还原不会成功
建议自己生成版本号,不要让编译器自动添加;自己定义,版本号不会随修改类的变化而变化

**transient关键字:**在序列化中,用于忽略该关键字修饰的属性

被修饰的属性将不会被忽略,不会序列化记录,可以达到省略存储空间的目的,减少不必要的开销

但是相应的该属性的信息也没有了,恢复了默认值

代码示例

package io;import java.io.Serializable;
import java.util.Arrays;//实现Serializable,记得要导包
public class Person implements Serializable{private static final long serialVersionUID = 1L;//序列化版本号,java会默认指定加上private String name;private int age;private String gender;private String[] otherInfo;public Person() {}public Person(String name, int age, String gender, String[] otherInfo) {this.name = name;this.age = age;this.gender = gender;this.otherInfo = otherInfo;}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 String getGender() {return gender;}public void setGender(String gender) {this.gender = gender;}public String[] getOtherInfo() {return otherInfo;}public void setOtherInfo(String[] otherInfo) {this.otherInfo = otherInfo;}@Overridepublic String toString() {return name+","+age+","+gender+","+Arrays.toString(otherInfo);}
}

2、类对象的写入(对象输出流)

步骤:

  1. 创建需要写入文件的实例化对象
  2. 创建文件输出流(低级流),传入文件路径
  3. 创建对象输出流(高级流),传入低级流
  4. 将对象通过对象流写入文件,调用对象流的写入对象的方法(oos.writeObject§;)
  5. 关闭对象输出流

注意事项:

  1. 在第四步中要注意对象流的写入方法方法可能抛出:NotSerializableException
    这说明写出的对象所属的类没有实现Serializable接口,我们需要在该类中实现该接口
  2. 写入文件后发现该文件的实际数据量比当前对象保存的内容要大
    这是因为这组字节除了包含了该对象的数据外,还含有这个对象的结构信息
    如果想减少不必要的开销,我们可以用 transient 关键字修饰不必要的属性

代码示例

package io;import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;/*** 对象输出流* @author Tian**/
public class OOSDemo {public static void main(String[] args) throws IOException {/** 将一个Person实例写入文件Person.obj中*///实例化对象String name = "吴素";int age = 22;String gender = "女";String[] otherInfo = {"陆地剑仙","佩剑","大凉龙雀","此剑抚平天下不平事","此剑无愧天下有愧人"};Person p = new Person(name,age,gender,otherInfo);//创建文件输出流FileOutputStream fos = new FileOutputStream("./Person.obj");//创建对象输出流ObjectOutputStream oos = new ObjectOutputStream(fos);//写出数据,调用对象输出流的写入对象方法//该方法可能抛出:NotSerializableException//当写出的对象所属的类没有实现Serializable接口时就会抛出该异常oos.writeObject(p);/** 写入文件后发现该文件的实际数据量比当前对象保存的内容要大* 这是因为这组字节除了包含了该对象的数据外* 还含有这个对象的结构信息*/System.out.println("写出完毕!");//关闭高级流oos.close();}
}

3、类对象的读出(对象输入流)

步骤:

  1. 创建文件输入流(低级流),传入文件路径
  2. 创建对象输入流(高级流),传入低级流
  3. 创建引用,接收读取的对象,通过ois.readObject()方法读取对象
  4. 关闭对象输入流

注意事项:

  1. 在第三步中,我们需要先创建一个相应对象,并且读取出来的对象要注意强转为我们新建引用的对象
  2. 注意如果文件中的数据不是相应的数据类型会报ClassNotFoundException的异常

ps. 在进行文件对象的读取时,我们进行了反序列化操作(把字节转换为对应数据)

代码示例:

package io;import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;/*** 对象输入流* @author Tian**/
public class OISDemo {public static void main(String[] args) throws ClassNotFoundException, IOException {/** 将Person.obj文件中的对象读取出来*///创建文件输入流FileInputStream fis = new FileInputStream("./Person.obj");//创建对象输入流ObjectInputStream ois = new ObjectInputStream(fis);//读入数据//Object p = ois.readObject();//需要强转为对应的对象类型//要注意,如果文件中的数据不是相应的数据类型会报ClassNotFoundException的异常//这里进行了反序列化:把字节转换为对应数据Person p = (Person) ois.readObject();System.out.println(p);ois.close();}
}

ps.文件流、缓冲流、对象流为字节流

Java标准的IO操作相关推荐

  1. java中的IO操作总结

    java中的IO操作 在java中IO涉及的范围比较大,本文主要针对文件内容的读写 对于文件内容的操作主要分为两大类: 字符流:有两个抽象类 writer Reader 其对应子类FileWriter ...

  2. java中的IO操作总结(一)

    转载:http://www.cnblogs.com/nerxious/archive/2012/12/15/2818848.html    所谓IO,也就是Input与Output的缩写.在java中 ...

  3. java中的IO操作之File类

    Java的集合框架:  类和接口存在于java.util包中. Java的IO:               类和接口存在于java.io包中. 学习方法:  文档在手,天下我有! --------- ...

  4. Java学习笔记---IO操作

    一.文件的创建 ------------------------------------------------------- File类,表示磁盘上的文件或目录,可对文件或目录进行操作.    * ...

  5. Java之IO操作总结

    所谓IO,也就是Input与Output的缩写.在java中,IO涉及的范围比较大,这里主要讨论针对文件内容的读写 其他知识点将放置后续章节 对于文件内容的操作主要分为两大类 分别是: 字符流 字节流 ...

  6. Android技能树 — Android存储路径及IO操作小结

    前言 最近过年刚上来,打算把自己的Android知识都整理一下. Android技能书系列: Android基础知识 Android技能树 - 动画小结 Android技能树 - View小结 And ...

  7. Java学习笔记-IO

    IO IO流概述 可以将数据传输操作,看作一种数据的流动,按照流动的方向分为输入(Input)和输出(Output) java中的IO操作主要指的是java.io包下的一些常用类的使用,通过这些常用类 ...

  8. JAVA基础编程——IO编程

    JAVA中的IO操作主要依赖java.io包来实现,该包主要包括五个类和一个接口: 五个类:File.InputStream.OutputStream.Reader.Wirter 一个接口:Seria ...

  9. Java学习-07 IO学习

    Java学习-07 IO学习 I : 即input,代表读取.O:即output,代表输出. 1.File 主要字段: 示例: System.out.println(File.pathSeparato ...

最新文章

  1. Android中的BuildConfig类怎么来的
  2. SVCHOST.exe进程之谜
  3. Docker技术入门与实战 第二版-学习笔记-9-Docker Compose 项目-2-Compose 命令说明
  4. 实例讲解如何利用jQuery设置图片居中放大或者缩小
  5. struts2无法调用类静态方法的解决办法
  6. IDEA编译时出现“cannot resolve symbol“的问题时的解决方法。
  7. 使用SQL Server发布数据库快照遇到错误:对路径”xxxxx“访问被拒绝的解决方法...
  8. 5.mybatis实战教程(mybatis in action)之五:与spring3集成(附源码)
  9. android 菜鸟面单打印_菜鸟Android
  10. 4位数字排列组合(所有组合与出现一次)
  11. 儿子懂得心痛他爸爸了
  12. linux pptpd源码,Centos 7 源码安装pptpd
  13. Latex texstudio法国人名字上面的一撇,声调输入
  14. 敏捷项目管理的前世今生及应用-Part 2(之3355)
  15. php yii应用运维,Yii 框架应用(Applications)操作实例详解
  16. Eclypse-Z7 + Zmod ADC 1410 基础环境搭建(SDK部分)
  17. 用C#.NET 与Webdriver写的抓取网页信息的小工具
  18. Surface pro 4 使用心得
  19. 参加ACM比赛所需的基础知识(转)
  20. matlab 文字版,MATLAB图书合集×110本免费奉送(All MATLAB Books Collection)文字版[PDF]

热门文章

  1. [安装之2] 台式计算机加固态硬盘,台式机添加固态硬盘教程_台式主机固态硬盘怎么安装
  2. miui系统神隐模式导致app后台服务无法连接网络
  3. android神隐模式,涨姿势!MIUI 中竟然有这么多隐藏功能
  4. php判断一个数组是否存在在另一个数组中
  5. python画熊猫代码_超清字符画——Python代码
  6. python 输入五个数_python实现输入五个数并求平均值
  7. Ecstore可被访问外部接口的详细配置方式
  8. matlab箱图所有点,MATLAB:多个不同维度的箱线图画在一起
  9. C语言简易程序设计————15、正整数分解质因数
  10. python对图片进行马赛克处理