<span style="font-family: Arial, Helvetica, sans-serif;"> ------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------</span>
在学习Java的SE基础部分时,一重要知识点就是IO流操作。这是因为流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称
为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。
Java中IO流可以根据处理数据类型的不同分为:字符流和字节流;根据数据流向不同分为:输入流和输出流 。
那么什么时候用字符流,什么时间用字节流呢,通过学习和自己的理解,简单的总结为一句话,所以传输都可以用字节流,文字用字符流,其他(图片、文件)用字节流处
理。这只是我个人的理解,如果有误还请好心的你指正。
1.输入字节流InputStreamIO 中输入字节流的继承图可见上图,可以看出:
InputStream 是所有的输入字节流的父类,它是一个抽象类。ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三种基本的介质流,它们分别从Byte 数组、StringBuffer、和本地文件中读取数据。ObjectInputStream 和所有FilterInputStream 的子类都是装饰流(装饰器模式的主角)。
OutputStream 是所有的输出字节流的父类,它是一个抽象类。ByteArrayOutputStream、FileOutputStream 是两种基本的介质流,它们分别向Byte 数组、和本地文件中写入数据。PipedOutputStream 是向与其它线程共用的管道中写入数据,ObjectOutputStream 和所有FilterOutputStream 的子类都是装饰流。
这张图是Java流操作有关的类或接口。下面这张图将详细解释Java流类结构:
话不多说,上代码,首先看看字节流吧。代码的思想也是由浅入深,最终变成常用形式。
package com.vince.bytestream;
/**
* 字节流输入
* */
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
public class InputStreamDemo {
/**
* 字节输入流读取方式一:每一次读取一个字节
* */
public static void read1(){
try {
//构造一个字节输入流对象
InputStream in = new FileInputStream("e:\\1.txt");
int b = -1;//-1表示没有数据
while((b=in.read())!=-1){
System.out.print((char)b);
}
//关闭
in.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 字节输入流读取方式二:一次性读取所有字节
* */
public static void read2(){
try {
//构造一个字节输入流对象
File f = new File("e:\\1.txt");
InputStream in = new FileInputStream(f);
//根据文件的大小构造字节数组
byte[] bytes = new byte[(int)f.length()];
int len = in.read(bytes);
System.out.println(new String(bytes));
System.out.println("len="+len);
//关闭
in.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 字节输入流读取方式三:每次读取指定大小的字节
* */
public static void read3(){
try {
//构造一个字节输入流对象
File f = new File("e:\\1.txt");
InputStream in = new FileInputStream(f);
//根据文件的大小构造字节数组
byte[] bytes = new byte[10];
int len = -1;//每次读取的实际长度
StringBuilder sb = new StringBuilder();
while((len = in.read(bytes))!=-1){
sb.append(new String(bytes,0,len));
//sb.append(new String(bytes));如果用这个会有问题,
//数组内容是覆盖,最后一次可能用不了10个,只覆盖3个
//那么后面6个将不是我们需要的愿内容
}
//关闭
in.close();
System.out.println(sb);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
read2();
//System.out.println("success");
}
}
package com.vince.bytestream;
/**
* 字节流输出
* */
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class OutputStreamDemo {
/**
* 字节输出流的方式一:每次输出一个字节
* */
public static void write1(){
try {
//创建一个文件字节输出流
OutputStream out = new FileOutputStream("e:\\1.txt");
String info = "Hello,IO";
byte[] bytes = info.getBytes();
for(int i=0;i<bytes.length;i++){
out.write(bytes[i]);//向文件中输出
}
//关闭流
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 字节输出流的方式二:每次输出指定大小的字节
* */
public static void write2(){
try {
//创建一个文件字节输出流
OutputStream out = new FileOutputStream("e:\\1.txt");
String info = "Hello,xiaobai";
byte[] bytes = info.getBytes();
out.write(bytes);//输出一个字节数组
//关闭流
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 字节输出流的方式二:每次输出指定大小的字节.追加
* */
public static void write3(){
try {
//创建一个文件字节输出流
OutputStream out = new FileOutputStream("e:\\1.txt");//("e:\\1.txt,true")表示追加
String info = "Hello,xiaobai";
byte[] bytes = info.getBytes();
out.write(bytes,0,5);//输出一个字节数组中指定范围的字节
//关闭流
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
//write1();
//write2();
write3();
System.out.println("success");
}
}
<span style="white-space:pre"> </span>字节流看完了,接下来我们看看字符流。
<span style="white-space:pre"> </span>字节流与字符流有什么区别呢?对于一个纯文本文件,字符流可以读取,<span style="font-family: Arial, Helvetica, sans-serif;">可以如果用字节流对UTF-8或Uicode进行读取可能会出现乱码,因此就有了专门对文本操作的字节流。字节流分为两类:Reader和Writer。</span>
<span style="white-space:pre"> 在上面的继承关系图中可以看出:
</span>
<span style="white-space:pre"> </span>Reader
<span style="font-family: Arial, Helvetica, sans-serif;"> 1、Reader 是所有的输入字符流的父类,它是一个抽象类。</span><span style="white-space:pre">
2、CharReader、StringReader 是两种基本的介质流,它们分别将Char 数组、String中读取数据。PipedReader 是从与其它线程共用的管道中读取数据。
3、BufferedReader 很明显就是一个装饰器,它和其子类负责装饰其它Reader 对象。
4、FilterReader 是所有自定义具体装饰流的父类,其子类PushbackReader 对Reader 对象进行装饰,会增加一个行号。
5、InputStreamReader 是一个连接字节流和字符流的桥梁,它将字节流转变为字符流。FileReader 可以说是一个达到此功能、常用的工具类,在其源代码中明 显使用了将FileInputStream 转变为Reader 的方法。我们可以从这个类中得到一定的技巧。Reader 中各个类的用途和使用方法基本和InputStream 中的类 使用一致。后面会有Reader 与InputStream 的对应关系</span>
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>Writer
<span style="white-space:pre"> 1、Writer 是所有的输出字符流的父类,它是一个抽象类。
2、CharArrayWriter、StringWriter 是两种基本的介质流,它们分别向Char 数组、String 中写入数据。PipedWriter 是向与其它线程共用的管道中写 </span> <span style="white-space:pre">入数据,
3、BufferedWriter 是一个装饰器为Writer 提供缓冲功能。
4、PrintWriter 和PrintStream 极其类似,功能和使用也非常相似。
5、OutputStreamWriter 是OutputStream 到Writer 转换的桥梁,它的子类FileWriter 其实就是一个实现此功能的具体类(具体可以研究一SourceCod </span> <span style="white-space:pre">e)。功能和使用和OutputStream 极其类似,后面会有它们的对应图。</span>
</pre><pre name="code" class="java"><span style="white-space:pre"> </span>通过下面的代码,加深Reader和Writer的使用吧。读者可以把以下代码复制下来到自己的java工具中运行调试。
<pre name="code" class="java"><span style="white-space:pre">package IO字符流;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException; </span>
<span style="white-space:pre"></span><pre name="code" class="java">public class The_1_Reader {
public static void main(String[] args) {
//创建一个文件读取对象,和指定名称的文件相关联。
//要保证该文件是已经存在的,如果不存在,会发生异常
FileReader fr = null;
try {
fr = new FileReader("e:\\text1.txt");
//调用读取流对象的read方法
// int ch;
//一次读一个字符,而且会依次往下读
// ch = fr.read();
// System.out.println("ch="+(char)ch);
int len = -1;
while((len = fr.read())!=-1){
System.out.print("len="+(char)len);//注意print 如果println数据超出1024会换行
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
package IO字符流;
import java.io.FileWriter;
import java.io.IOException;
/**
* IO流
* 流按操作数据分为两种:字节流与字符流
* 流按流向分为:输入流、输出流
*
* 字节流的抽象基类
* InputStream,OutputStream
* 字符流的抽象基类
* Reader,Writer
* 这四个类派生出来的子类名称都是以其父类名作为子类名的后缀,前缀名为该类的功能
* 如:InputStream 的子类 FileInputStream
* Reader 的子类 FileReader
*
* */
public class The_1_Writer {
public static void main(String[] args) {
//在外面进行引用,在try中进行初始化
FileWriter fw = null;
try {
//创建一个FileWriter对象。该对象已被初始化就必须要明确被初始化的文件
//而且该文件会被创建到指定的目录下,如果该目录下已有同名文件,将被覆盖
//其实该步就是在明确数据存放的目的地。
fw = new FileWriter("e:\\text1.txt");
//调用write()方法,将字符串写入到流中
fw.write("abcde");
//刷新流对象中缓冲的数据。
//将数据刷到目的地中。
fw.flush();
} catch (IOException e) {
e.printStackTrace();
} finally{
try {
//关闭流资源,但是关闭前会刷新一次内部的缓冲中的数据
//将数据刷新到目的地中
//和flush区别:flush刷新后,流可以继续使用,close刷新后,会关闭流
if(fw!=null)
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}