Java标准的IO操作
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、类对象的写入(对象输出流)
步骤:
- 创建需要写入文件的实例化对象
- 创建文件输出流(低级流),传入文件路径
- 创建对象输出流(高级流),传入低级流
- 将对象通过对象流写入文件,调用对象流的写入对象的方法(oos.writeObject§;)
- 关闭对象输出流
注意事项:
- 在第四步中要注意对象流的写入方法方法可能抛出:NotSerializableException
这说明写出的对象所属的类没有实现Serializable接口,我们需要在该类中实现该接口 - 写入文件后发现该文件的实际数据量比当前对象保存的内容要大
这是因为这组字节除了包含了该对象的数据外,还含有这个对象的结构信息
如果想减少不必要的开销,我们可以用 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、类对象的读出(对象输入流)
步骤:
- 创建文件输入流(低级流),传入文件路径
- 创建对象输入流(高级流),传入低级流
- 创建引用,接收读取的对象,通过ois.readObject()方法读取对象
- 关闭对象输入流
注意事项:
- 在第三步中,我们需要先创建一个相应对象,并且读取出来的对象要注意强转为我们新建引用的对象
- 注意如果文件中的数据不是相应的数据类型会报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操作相关推荐
- java中的IO操作总结
java中的IO操作 在java中IO涉及的范围比较大,本文主要针对文件内容的读写 对于文件内容的操作主要分为两大类: 字符流:有两个抽象类 writer Reader 其对应子类FileWriter ...
- java中的IO操作总结(一)
转载:http://www.cnblogs.com/nerxious/archive/2012/12/15/2818848.html 所谓IO,也就是Input与Output的缩写.在java中 ...
- java中的IO操作之File类
Java的集合框架: 类和接口存在于java.util包中. Java的IO: 类和接口存在于java.io包中. 学习方法: 文档在手,天下我有! --------- ...
- Java学习笔记---IO操作
一.文件的创建 ------------------------------------------------------- File类,表示磁盘上的文件或目录,可对文件或目录进行操作. * ...
- Java之IO操作总结
所谓IO,也就是Input与Output的缩写.在java中,IO涉及的范围比较大,这里主要讨论针对文件内容的读写 其他知识点将放置后续章节 对于文件内容的操作主要分为两大类 分别是: 字符流 字节流 ...
- Android技能树 — Android存储路径及IO操作小结
前言 最近过年刚上来,打算把自己的Android知识都整理一下. Android技能书系列: Android基础知识 Android技能树 - 动画小结 Android技能树 - View小结 And ...
- Java学习笔记-IO
IO IO流概述 可以将数据传输操作,看作一种数据的流动,按照流动的方向分为输入(Input)和输出(Output) java中的IO操作主要指的是java.io包下的一些常用类的使用,通过这些常用类 ...
- JAVA基础编程——IO编程
JAVA中的IO操作主要依赖java.io包来实现,该包主要包括五个类和一个接口: 五个类:File.InputStream.OutputStream.Reader.Wirter 一个接口:Seria ...
- Java学习-07 IO学习
Java学习-07 IO学习 I : 即input,代表读取.O:即output,代表输出. 1.File 主要字段: 示例: System.out.println(File.pathSeparato ...
最新文章
- Android中的BuildConfig类怎么来的
- SVCHOST.exe进程之谜
- Docker技术入门与实战 第二版-学习笔记-9-Docker Compose 项目-2-Compose 命令说明
- 实例讲解如何利用jQuery设置图片居中放大或者缩小
- struts2无法调用类静态方法的解决办法
- IDEA编译时出现“cannot resolve symbol“的问题时的解决方法。
- 使用SQL Server发布数据库快照遇到错误:对路径”xxxxx“访问被拒绝的解决方法...
- 5.mybatis实战教程(mybatis in action)之五:与spring3集成(附源码)
- android 菜鸟面单打印_菜鸟Android
- 4位数字排列组合(所有组合与出现一次)
- 儿子懂得心痛他爸爸了
- linux pptpd源码,Centos 7 源码安装pptpd
- Latex texstudio法国人名字上面的一撇,声调输入
- 敏捷项目管理的前世今生及应用-Part 2(之3355)
- php yii应用运维,Yii 框架应用(Applications)操作实例详解
- Eclypse-Z7 + Zmod ADC 1410 基础环境搭建(SDK部分)
- 用C#.NET 与Webdriver写的抓取网页信息的小工具
- Surface pro 4 使用心得
- 参加ACM比赛所需的基础知识(转)
- matlab 文字版,MATLAB图书合集×110本免费奉送(All MATLAB Books Collection)文字版[PDF]
热门文章
- [安装之2] 台式计算机加固态硬盘,台式机添加固态硬盘教程_台式主机固态硬盘怎么安装
- miui系统神隐模式导致app后台服务无法连接网络
- android神隐模式,涨姿势!MIUI 中竟然有这么多隐藏功能
- php判断一个数组是否存在在另一个数组中
- python画熊猫代码_超清字符画——Python代码
- python 输入五个数_python实现输入五个数并求平均值
- Ecstore可被访问外部接口的详细配置方式
- matlab箱图所有点,MATLAB:多个不同维度的箱线图画在一起
- C语言简易程序设计————15、正整数分解质因数
- python对图片进行马赛克处理