频道栏目
首页 > 程序开发 > 软件开发 > Java > 正文
Java IO流知识树讲解
2018-03-02 13:51:51         来源:finish_dream的博客  
收藏   我要投稿

1. 流分为字节流和字符流

2. 字节流下面常用的又有数据流和对象流

3. 字符流下面常用的又有缓存流

\

文件对象

文件和文件夹都用File表示

//file path : 文件的绝对路径或相对路径File file=new File("file path");

注:文件路径可能不存在

File的常用方法自行查阅API

什么是流(Stream),流就是一系列的数据

当不同的介质之间有数据交互的时候,JAVA就使用流来实现。

数据源可以是文件,还可以是数据库,网络甚至是其他的程序

比如读取文件的数据到程序中,站在程序的角度来看,就叫做输入流

输入流: InputStream

输出流:OutputStream

3.1、字节流,关闭流的方式

以字节的形式读取和写入数据

所有的数据存放在计算机中都是以数字的形式存放的。 所以字母就需要转换为数字才能够存放。

比如A就对应的数字65,a对应的数字97. 不同的字母和符号对应不同的数字,就是一张码表。

ASCII是这样的一种码表。 字包含简单的英文字母,符号,数字等等。 不包含中文,德文,俄语等复杂的。

3.1.1、输入字节流

InputStream是字节输入流,同时也是抽象类,只提供方法的生命,不提供方法的实现。

FileInputStream是InputStream的子类以FIleInputStream为例进行文件读取:

package stream;

import java.io.File;

import java.io.FileInputStream;

import java.io.IOException;

public class TestStream {

public static void main(String[] args) {

try {

//准备文件lol.txt其中的内容是AB,对应的ASCII分别是65 66

File f =new File("d:/lol.txt");

//创建基于文件的输入流

FileInputStream fis =new FileInputStream(f);

//创建字节数组,其长度就是文件的长度

byte[] all =new byte[(int) f.length()];

//以字节流的形式读取文件所有内容

fis.read(all);

for (byte b : all) {

//打印出来是65 66

System.out.println(b);

}

//每次使用完流,都应该进行关闭

fis.close();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

3.1.2、输出字节流

OutputStream是字节输出流,同时也是抽象类,只提供方法声明,不提供方法的具体实现。

FileOutputStream 是OutputStream子类,以FileOutputStream 为例向文件写出数据

注: 如果文件d:/lol2.txt不存在,写出操作会自动创建该文件。

但是如果是文件 d:/xyz/lol2.txt,而目录xyz又不存在,会抛出异常

package stream;

import java.io.File;

import java.io.FileOutputStream;

import java.io.IOException;

public class TestStream {

public static void main(String[] args) {

try {

// 准备文件lol2.txt其中的内容是空的

File f = new File("d:/lol2.txt");

// 准备长度是2的字节数组,用88,89初始化,其对应的字符分别是X,Y

byte data[] = { 88, 89 };

// 创建基于文件的输出流

FileOutputStream fos = new FileOutputStream(f);

// 把数据写入到输出流

fos.write(data);

// 关闭输出流

fos.close();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

3.1.3、在try中关闭

在try的作用域里关闭文件输入流,在前面的示例中都是使用这种方式,这样做有一个弊端;

如果文件不存在,或者读取的时候出现问题而抛出异常,那么就不会执行这一行关闭流的代码,存在巨大的资源占用隐患。 不推荐使用

package stream;

import java.io.File;

import java.io.FileInputStream;

import java.io.IOException;

public class TestStream {

public static void main(String[] args) {

try {

File f = new File("d:/lol.txt");

FileInputStream fis = new FileInputStream(f);

byte[] all = new byte[(int) f.length()];

fis.read(all);

for (byte b : all) {

System.out.println(b);

}

// 在try 里关闭流

fis.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

3.1.4、在finally中关闭

这是标准的关闭流的方式

1. 首先把流的引用声明在try的外面,如果声明在try里面,其作用域无法抵达finally.

2. 在finally关闭之前,要先判断该引用是否为空

3. 关闭的时候,需要再一次进行try catch处理

这是标准的严谨的关闭流的方式,但是看上去很繁琐,所以写不重要的或者测试代码的时候,都会采用上面的有隐患try的方式,因为不麻烦~

package stream;

import java.io.File;

import java.io.FileInputStream;

import java.io.IOException;

public class TestStream {

public static void main(String[] args) {

File f = new File("d:/lol.txt");

FileInputStream fis = null;

try {

fis = new FileInputStream(f);

byte[] all = new byte[(int) f.length()];

fis.read(all);

for (byte b : all) {

System.out.println(b);

}

} catch (IOException e) {

e.printStackTrace();

} finally {

// 在finally 里关闭流

if (null != fis)

try {

fis.close();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

3.1.5、使用try()的方式

把流定义在try()里,try,catch或者finally结束的时候,会自动关闭

这种编写代码的方式叫做 try-with-resources, 这是从JDK7开始支持的技术

所有的流,都实现了一个接口叫做 AutoCloseable,任何类实现了这个接口,都可以在try()中进行实例化。 并且在try, catch, finally结束的时候自动关闭,回收相关资源。

package stream;

import java.io.File;

import java.io.FileInputStream;

import java.io.IOException;

public class TestStream {

public static void main(String[] args) {

File f = new File("d:/lol.txt");

//把流定义在try()里,try,catch或者finally结束的时候,会自动关闭

try (FileInputStream fis = new FileInputStream(f)) {

byte[] all = new byte[(int) f.length()];

fis.read(all);

for (byte b : all) {

System.out.println(b);

}

} catch (IOException e) {

e.printStackTrace();

}

}

}

综合实例

\
\

3.2、字符流,中文编码问题

Reader是字符输入流

Writer是字符输出流

专门用于字符形式读取和写入数据

3.2.1、使用字符流读取文件

FileReader是Reader子类,以FileReader为例进行文件读取

package stream;

import java.io.File;

import java.io.FileReader;

import java.io.IOException;

public class TestStream {

public static void main(String[] args) {

// 准备文件lol.txt其中的内容是AB

File f = new File("d:/lol.txt");

// 创建基于文件的Reader

try (FileReader fr = new FileReader(f)) {

// 创建字符数组,其长度就是文件的长度

char[] all = new char[(int) f.length()];

// 以字符流的形式读取文件所有内容

fr.read(all);

for (char b : all) {

// 打印出来是A B

System.out.println(b);

}

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

3.2.2、使用字符流把字符串写到文件

FileWriter是Writer的子类,以FileWriter为例把字符串写到文件

package stream;

import java.io.File;

import java.io.FileWriter;

import java.io.IOException;

public class TestStream {

public static void main(String[] args) {

// 准备文件lol2.txt

File f = new File("d:/lol2.txt");

// 创建基于文件的Writer

try (FileWriter fr = new FileWriter(f)) {

// 以字符流的形式把数据写入到文件中

String data="abcdefg1234567890";

char[] cs = data.toCharArray();

fr.write(cs);

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

3.2.3、常见编码

工作后经常接触的编码方式有如下几种:

ISO-8859-1 ASCII 数字和西欧字母

GBK GB2312 BIG5 中文

UNICODE (统一码,万国码)

其中

ISO-8859-1 包含 ASCII

GB2312 是简体中文,BIG5是繁体中文,GBK同时包含简体和繁体以及日文。

UNICODE 包括了所有的文字,无论中文,英文,藏文,法文,世界所有的文字都包含其中

3.2.4、UNICODE和UTF

UNICODE因为要存放所有的数据,所以完全按照UNICODE的方式来存储数据,就会有很大的浪费

在这种情况下,就出现了UNICODE的各种减肥子编码,比如UTF-8对数字和字符就使用一个字节,而对汉字就使用3个字节,从而达到了减肥还能保证健康的效果

\

3.2.5、Java采用的Unicode

写在.java源代码中的汉字,在执行之后,都会变成JVM中的字符。

而这些中文字符采用的编码方式,都是使用UNICODE.

3.3、缓存流

以介质是硬盘为例,字节流和字符流的弊端:

在每一次读写的时候,都会访问硬盘。 如果读写的频率比较高的时候,其性能表现不佳。

为了解决以上弊端,采用缓存流。

缓存流在读取的时候,会一次性读较多的数据到缓存中,以后每一次的读取,都是在缓存中访问,直到缓存中的数据读取完毕,再到硬盘中区读取。

就好比吃饭,不用缓存就是每吃一口都到锅里去铲。用缓存就是先把饭盛到碗里,碗里的吃完了,再到锅里去铲

缓存流在写入数据的时候,会先把数据写入到缓存区,直到缓存区达到一定的量,才把这些数据,一起写入到硬盘中去。按照这种操作模式,就不会像字节流,字符流那样每写一个字节都访问硬盘,从而减少了IO操作

3.3.1、使用缓存流读取数据

缓存字符输入流 BufferedReader 可以一次读取一行数据

package stream;

import java.io.BufferedReader;

import java.io.File;

import java.io.FileReader;

import java.io.IOException;

public class TestStream {

public static void main(String[] args) {

// 准备文件lol.txt其中的内容是

// garen kill teemo

// teemo revive after 1 minutes

// teemo try to garen, but killed again

File f = new File("d:/lol.txt");

// 创建文件字符流

// 缓存流必须建立在一个存在的流的基础上

try (

FileReader fr = new FileReader(f);

BufferedReader br = new BufferedReader(fr);

)

{

while (true) {

// 一次读一行

String line = br.readLine();

if (null == line)

break;

System.out.println(line);

}

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

3.3.2、使用缓存流写出数据

PrintWriter 缓存字符输出流, 可以一次写出一行数据

package stream;

import java.io.File;

import java.io.FileWriter;

import java.io.IOException;

import java.io.PrintWriter;

public class TestStream {

public static void main(String[] args) {

// 向文件lol2.txt中写入三行语句

File f = new File("d:/lol2.txt");

try (

// 创建文件字符流

FileWriter fw = new FileWriter(f);

// 缓存流必须建立在一个存在的流的基础上

PrintWriter pw = new PrintWriter(fw);

) {

pw.println("garen kill teemo");

pw.println("teemo revive after 1 minutes");

pw.println("teemo try to garen, but killed again");

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

3.3.3、flush

有的时候,需要立即把数据写入到硬盘,而不是等缓存满了才写出去。 这时候就需要用到flush

package stream;

import java.io.File;

import java.io.FileWriter;

import java.io.IOException;

import java.io.PrintWriter;

public class TestStream {

public static void main(String[] args) {

//向文件lol2.txt中写入三行语句

File f =new File("d:/lol2.txt");

//创建文件字符流

//缓存流必须建立在一个存在的流的基础上

try(FileWriter fr = new FileWriter(f);PrintWriter pw = new PrintWriter(fr);) {

pw.println("garen kill teemo");

//强制把缓存中的数据写入硬盘,无论缓存是否已满

pw.flush();

pw.println("teemo revive after 1 minutes");

pw.flush();

pw.println("teemo try to garen, but killed again");

pw.flush();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

点击复制链接 与好友分享!回本站首页
上一篇:Java 常用工具类之分页sql语句limit处理讲解
下一篇:java spring 上下文和spring mvc上下文和web应用上下文servletContext之间的关系
相关文章
图文推荐
点击排行

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站