java IO流
Posted D大调奏鸣曲_第七序章_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java IO流相关的知识,希望对你有一定的参考价值。
目录
序
做自己吧,别人都已经有人做了。
——王尔德
一、IO流开篇
1、概念
流:是一抽象概念,是对数据传输的总称。也就是说数据在设备间的传输称为流。更具体一点,是内存与存储设备之间传输数据的通道。
IO流:对于数据的传输,可以看做是一种数据的流动,按照流动的方向,以内存为基准,分为输入input 和输出output ,即流向内存是输入流,流出内存的输出流。
Java中I/O操作主要是指使用java.io包下的内容,进行输入、输出操作。输入也叫做读取数据,输出也叫做作写出数据。
2、流的分类
按方向分
- 输入流: 将 < 存储设备 > 中的内容读入到 < 内存 > 中.
- 输出流: 将 < 内存 > 中的内容写入到 < 存储设备 > 中.
按代为分
- 字节流: 以字节为单位, 可以读写所有数据.
- 字符流: 以字符为单位, 只能读写文本数据.
按功能分
- 节点流: 具有实际传输数据的读写功能.
- 过滤流: 在街电流的基础之上增强功能.
(详细解释:
节点流:从特定的地方读写的流类,例如:磁盘或一块内存区域。
过滤流:使用节点流作为输入或输出。过滤流是使用一个已经存在的输入流或输出流连接创建的。
FileInputStream和FileOutputStream,节点流,用于从文件中读取或往文件中写入字节流。如果在构造FileOutputStream时,文件已经存在,则覆盖这个文件。
BufferedInputStream和BufferedOutputStream,过滤流,需要使用已经存在的节点流来构造,提供带缓冲的读写,提高了读写的效率。
DataInputStream和DataOutputStream,过滤流,需要使用已经存在的节点流来构造,提供了读写Java中的基本数据类型的功能。)
3、IO流的作用
用来处理设备间数据传输问题
常见的应用:文件复制、文件上传、文件下载
4、IO流的使用场景
如果操作的是纯文本文件,优先使用字符流
如果操作的是二进制文件,优先使用字节流
如果不确定,则优先使用字节流
二、字节流
1、字节流抽象基类
InputStream:字节输入流的所有类的超类
OutputStream:字节输出流的所有类的超类
子类名特点:子类名称都是以其父类名作为子类名的后缀
2、字节流写数据
(1)基本步骤
创建FileOutputStream对象,关联到一个文件路径
调用write()方法,写出数据
调用close()方法,释放资源
打开文件,查看内容
(2)三种方式
write(int b) 一次写一个字节数据
write(byte[] arr) 一次写一个字节数组
write(byte[] arr,int index,int len) 写字节数组的一部分
(3)两个问题
如何写换行
调用write()方法,写出”\\r\\n”.getBytes()即可
如何文件续写
使用FileOutputStream(String name,boolean append)构造方法
构造方法中第二个参数传递true,则在文件末尾继续写数据
(4)异常处理
字节流写数据同时处理异常的重要步骤
将创建字节流对象和写出数据的代码放在try中
在catch中捕获IOException异常
在finally中进行释放资源
3、字节缓冲流
(1)基本分类&概述
BufferedOutputStream
类实现缓冲输出流。 通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用
BufferedInputStream
创建BufferedInputStream将创建一个内部缓冲区数组。 当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节
(2)构造方法
| BufferedOutputStream(OutputStream out) | 创建字节缓冲输出流对象 |
| BufferedInputStream(InputStream in) | 创建字节缓冲输入流对象 |
(3)代码演示
public class BufferStreamDemo {
public static void main(String[] args) throws IOException {
//字节缓冲输出流:BufferedOutputStream(OutputStream out)
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("myByteStream\\\\bos.txt"));
//写数据
bos.write("hello\\r\\n".getBytes());
bos.write("world\\r\\n".getBytes());
//释放资源
bos.close();
//字节缓冲输入流:BufferedInputStream(InputStream in)
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("myByteStream\\\\bos.txt"));
//一次读取一个字节数据
// int by;
// while ((by=bis.read())!=-1) {
// System.out.print((char)by);
// }
//一次读取一个字节数组数据
byte[] bys = new byte[1024];
int len;
while ((len=bis.read(bys))!=-1) {
System.out.print(new String(bys,0,len));
}
//释放资源
bis.close();
}
}
三、字符流
1、概念
由于字节流操作中文不是特别的方便,所以Java就提供字符流
字符流 = 字节流 + 编码表
(补充):中文的字节存储方式
用字节流复制文本文件时,文本文件也会有中文,但是没有问题,原因是最终底层操作会自动进行字节拼接成中文,如何识别是中文的呢?
汉字在存储的时候,无论选择哪种编码存储,第一个字节都是负数
2、分类
(1)字符流体系图
(2)字符输入流(Reader)
(3)字符输出流(Writer)
3、字符缓冲流
(1)概念
BufferedWriter
将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入,可以指定缓冲区大小,或者可以接受默认大小。默认值足够大,可用于大多数用途。
BufferedReader
从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取,可以指定缓冲区大小,或者可以使用默认大小。 默认值足够大,可用于大多数用途。
(2)构造方法
| BufferedWriter(Writer out) | 创建字符缓冲输出流对象 |
| BufferedReader(Reader in) | 创建字符缓冲输入流对象 |
(3)代码演示
public class BufferedStreamDemo01 {
public static void main(String[] args) throws IOException {
//BufferedWriter(Writer out)
BufferedWriter bw = new BufferedWriter(new FileWriter("myCharStream\\\\bw.txt"));
bw.write("hello\\r\\n");
bw.write("world\\r\\n");
bw.close();
//BufferedReader(Reader in)
BufferedReader br = new BufferedReader(new FileReader("myCharStream\\\\bw.txt"));
//一次读取一个字符数据
// int ch;
// while ((ch=br.read())!=-1) {
// System.out.print((char)ch);
// }
//一次读取一个字符数组数据
char[] chs = new char[1024];
int len;
while ((len=br.read(chs))!=-1) {
System.out.print(new String(chs,0,len));
}
br.close();
}
}
(4)字符缓冲流特有功能
void newLine()写一行行分隔符,行分隔符字符串由系统属性定义
String readLine()读一行文字。 结果包含行的内容的字符串,不包括任何行终止字符如果流的结尾已经到达,则为null
四、IO特殊操作流
1、标准输入输出流
public static final InputStream in:标准输入流。
通常该流对应于键盘输入或由主机环境或用户指定的另一个输入源。
使用步骤:
1.我们可以自己实现键盘录入输入。
BufferedReader(InputStreamReader(System.in));
调用readtLine()方法接收数据。
2.但是上面的方式太麻烦了,所以我们直接使用键盘输入的类
Scanner sc = new Scanner(System.in);
public static final PrintStream out:标准输出流。
通常该流对应于显示输出或由主机环境或用户指定的另一个输出目标。
使用步骤:
输出语句本质就是一个标准输出流
创建标准输出流对象:PrintStream ps = System.out;
调用print()方法可以输出不带换行效果的数据
调用println()方法可以输出带换行效果的数据
2、打印流
字节打印流:PrintStream
- PrintStream(String fileName):使用指定的文件名创建新的打印流。
- 使用继承父类的方法写数据,查看的时候会转码;使用自己的特有方法写数据,查看的数据原样输出。
- 可以改变输出语句的目的地。
字符打印流:PrintWriter
PrintWriter(String fileName):使用指定的文件名创建一个新的PrintWriter,而不需要自动执行刷新。
PrintWriter(Writer out, boolean autoFlush):
创建一个新的PrintWriter out:字符输出流。
autoFlush: 一个布尔值,如果为真,则println , printf ,或format方法将刷新输出缓冲区。
3、对象序列化流
对象序列化流( ObjectOutputStream):
将Java对象的原始数据类型和图形写入OutputStream。 可以使用ObjectInputStream读取(重构)对象。 可以通过使用流的文件来实现对象的持久存储。 如果流是网络套接字流,则可以在另一个主机上或另一个进程中重构对象 。
构造方法:
ObjectOutputStream(OutputStream out)
创建一个写入指定的OutputStream的ObjectOutputStream。
序列化对象的方法:
void writeObject(Object obj)
将指定的对象写入ObjectOutputStream。
4、对象反序列化流
对象反序列化流(ObjectInputStream):
反序列化先前使用ObjectOutputStream编写的原始数据和对象。
构造方法:
ObjectInputStream(InputStream in)
创建从指定的InputStream读取的ObjectInputStream
反序列化对象的方法:
Object readObject()
从ObjectInputStream读取一个对象
五、补充知识
1、集合(Properties集合)
(1)概念:
- 是一个Map体系的集合类
- Properties可以保存到流中或从流中加载
- 属性列表中的每个键及其对应的值都是一个字符串
(2)Properties作为Map集合的特有方法
1、Object setProperty(String key, String value)
设置集合的键和值,都是String类型,底层调用 Hashtable方法 put
2、String getProperty(String key)
使用此属性列表中指定的键搜索属性
3、Set<String> stringPropertyNames()
从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串
(3)Properties和IO流相结合的方法
1、void load(InputStream inStream)
从输入字节流读取属性列表(键和元素对)
2、void load(Reader reader)
从输入字符流读取属性列表(键和元素对)
3、void store(OutputStream out, String comments)
将此属性列表(键和元素对)写入此 Properties表中,以适合于使用 load(InputStream)方法的格式写入输出字节流
4、void store(Writer writer, String comments)
将此属性列表(键和元素对)写入此 Properties表中,以适合使用 load(Reader)方法的格式写入输出字符流
(4)、示例代码
public class PropertiesDemo03 {
public static void main(String[] args) throws IOException {
//把集合中的数据保存到文件
// myStore();
//把文件中的数据加载到集合
myLoad();
}
private static void myLoad() throws IOException {
Properties prop = new Properties();
//void load(Reader reader):
FileReader fr = new FileReader("myOtherStream\\\\fw.txt");
prop.load(fr);
fr.close();
System.out.println(prop);
}
private static void myStore() throws IOException {
Properties prop = new Properties();
prop.setProperty("itheima001","林青霞");
prop.setProperty("itheima002","张曼玉");
prop.setProperty("itheima003","王祖贤");
//void store(Writer writer, String comments):
FileWriter fw = new FileWriter("myOtherStream\\\\fw.txt");
prop.store(fw,null);
fw.close();
}
}
2、编码表
(1)什么是字符集
是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等。
计算机要准确的存储和识别各种字符集符号,就需要进行字符编码,一套字符集必然至少有一套字符编码。常见字符集有ASCII字符集、GBXXX字符集、Unicode字符集等。
(2)常见的字符集
ASCII字符集
ASCII:是基于拉丁字母的一套电脑编码系统,用于显示现代英语,主要包括控制字符(回车键、退格、换行键等)和可显示字符(英文大小写字符、阿拉伯数字和西文符号) 。
基本的ASCII字符集,使用7位表示一个字符,共128字符。ASCII的扩展字符集使用8位表示一个字符,共256字符,方便支持欧洲常用字符。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等
GBXXX字符集
GBK:最常用的中文码表。是在GB2312标准基础上的扩展规范,使用了双字节编码方案,共收录了21003个汉字,完全兼容GB2312标准,同时支持繁体汉字以及日韩汉字等。
Unicode字符集
UTF-8编码:可以用来表示Unicode标准中任意字符,它是电子邮件、网页及其他存储或传送文字的应用 中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。它使用一至四个字节为每个字符编码。
(3)编码规则
128个US-ASCII字符,只需一个字节编码
拉丁文等字符,需要二个字节编码
大部分常用字(含中文),使用三个字节编码
其他极少使用的Unicode辅助字符,使用四字节编码
3、serialVersionUID&transient
serialVersionUID
用对象序列化流序列化了一个对象后,假如我们修改了对象所属的类文件,读取数据会不会出问题呢?
会出问题,会抛出InvalidClassException异常。
如果出问题了,如何解决呢?
- 重新序列化
- 给对象所属的类加一个serialVersionUID
private static final long serialVersionUID = 42L;
transient
如果一个对象中的某个成员变量的值不想被序列化,又该如何实现呢?
给该成员变量加transient关键字修饰,该关键字标记的成员变量不参与序列化过程
示例代码:
学生类:
public class Student implements Serializable {
private static final long serialVersionUID = 42L;
private String name;
// private int age;
private transient int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = 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;
}
// @Override
// public String toString() {
// return "Student{" +
// "name='" + name + '\\'' +
// ", age=" + age +
// '}';
// }
}
测试类:
public class ObjectStreamDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// write();
read();
}
//反序列化
private static void read() throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("myOtherStream\\\\oos.txt"));
Object obj = ois.readObject();
Student s = (Student) obj;
System.out.println(s.getName() + "," + s.getAge());
ois.close();
}
//序列化
private static void write() throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("myOtherStream\\\\oos.txt"));
Student s = new Student("林青霞", 30);
oos.writeObject(s);
oos.close();
}
}
六、完结撒花ING
以上是关于java IO流的主要内容,如果未能解决你的问题,请参考以下文章
JAVA IO流相关代码(Serializable接口,管道流PipedInputStream类,RandomAccessFile类相关代码)
JAVA IO流相关代码(Serializable接口,管道流PipedInputStream类,RandomAccessFile类相关代码)