综叙
IO流是处理设备之间的数据传输的,Java对数据的操作是通过流的方式来完成,流按照数据分为:字节流和字符流按照流向分为:输入流和输出流。
字节流的抽象基类:InputStream,OutputStream
字符流的抽象基类:Reader,Writer
IO程序的书写过程:
导入IO包中的类
进行IO异常处理
在finally中对流进行关闭
1. 字符流
注意事项:
1,在写入之后要调用flush方法,将缓存中的数据清空到硬盘。
2,最后要在finally中关闭资源。
3,定义一个数组存储读取的字符,提高效率。
4,要做IO异常处理
练习:Copy一个文本文件
//复制一个文本文件。
/*
复制的原理:
就是用读取字符流流读取文本文件,再用写入字符流将读取到的写入到硬盘
步骤:
1,在创建一个文件,并写入测试数据。
2,定义读取流和该文件关联。
3,通过不断的读写完成数据存储。
4,关闭资源。
*/
import java.io.*;
class CopyText
{
public static void main(String[] args) throws IOException
{
copy();
}
public static void copy()
{
FileWriter fw = null;
FileReader fr = null;
try
{
fw = new FileWriter("123.txt");
fr = new FileReader("FileWriterDemo3.java");
char[] buf = new char[1024];
int len=0;
while((len=fr.read(buf))!=-1)
{
fw.write(buf,0,len);
}
}
catch (IOException e)
{
throw new RuntimeException("读写失败");
}
finally
{
if(fr!=null)
try
{
fr.close();
}
catch (IOException e)
{
}
if(fw!=null)
try
{
fw.close();
}
catch (IOException e)
{
}
}
}
}
缓存区:
通过加入缓冲区复制文本文件,提高读取效率,BufferedWriter,BufferedReader,缓存区是专门针对与流而存在的,在流的基础上对流进行了改进。
而LineNumberReader又在缓存区的基础上提供了对文本文件中的行计数的功能。我们把这样的思想叫做装饰设计模式。
装饰模式比继承要灵活。避免了继承体系臃肿。
而且降低了类于类之间的关系。
装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强功能。
所以装饰类和被装饰类通常是都属于一个体系中的。
练习:通过BufferedReader,BufferedWriter实现高效的复制
/*
通过缓冲区复制一个文本文件。
*/
import java.io.*;
class CopyTextByBuf
{
public static void main(String[] args)
{
BufferedReader bufr = null;
BufferedWriter bufw = null;
try
{
bufr = new BufferedReader(new FileReader("FileWriterDemo3.java"));
bufw = new BufferedWriter(new FileWriter("111.java"));
String line=null;
while((line=bufr.readLine())!=null)
{
bufw.write(line);
bufw.newLine();
bufw.flush();
}
}
catch (IOException e)
{
throw new RuntimeException("读写失败");
}
finally
{
try
{
if(bufr!=null)
bufr.close();
}
catch (IOException e)
{
throw new RuntimeException("读取关闭失败");
}
try
{
if(bufw!=null)
bufw.close();
}
catch (IOException e)
{
throw new RuntimeException("写入关闭失败");
}
}
}
}
2. 字节流
字节流不仅可以操作字符,还可以操作其他媒体文件也可以通过缓存区提高效率。
练习:高效复制MP3文件
/*
复制MP3
*/
import java.io.*;
class CopyMp3
{
public static void main(String[] args) throws IOException
{
copy_1();
}
public static void copy_1() throws IOException
{
BufferedInputStream bufis = new BufferedInputStream(new FileInputStream("1.mp3"));
BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("2.mp3"));
int by = 0;
while((by=bufis.read())!=-1)
{
bufos.write(by);
}
bufos.close();
bufis.close();
}
}
3. 转换流
字节流转换为字符流:InputStreamReader
有这样一种情况InputStream想要使用readLine()方法进行读取,但这个功能只有字符流才有,那么我们可以通过InputStreamReader来实现字节流向字符流的转换。
字符流转换为字节流:OutputStreamWriter
当我们想指定文件存储的的编码格式时就会用到。
附体系结构图:
![字符流结构](![https://img-blog.csdn.net/20150624220640652](https://img-blog.csdn.net/20150624221008034))
![字节流结构](https://img-blog.csdn.net/20150624220725067)
4. 打印流
该流提供了打印方法,可以将各种数据类型的数据都原样打印。
字节打印流:PrintStream永远不会抛出IOException,写入数据时可以自动刷新(实例化时传入是否可以自动刷新的参数)
PrintStream
构造函数可以接收的参数类型:
1,file对象。File
2,字符串路径。String
3,字节输出流。OutputStream
字符打印流:此类实现在PrintStream中的所有的实现方法,与PrintStream类不同如果启用了自动刷新则只有在调用printf,println或者是format中的一个方法的时候才能完成此操作。
PrintWriter
构造函数可以接收的参数类型:
1,file对象。File
2,字符串路径。String
3,字节输出流。OutputStream
4,字符输出流,Writer。
5. 序列流
SequenceInputStream表示其它输入流的逻辑串联,它从输入流的有序集合开始,并且从第一个输入流开始读取,直到到达文件的末尾接着从第二个输入流开始读取依次类推直到到达最后一个输入流的文件末尾。经常用于多文件的合并。
练习:将多个文件合并为一个。
public class SequenceDemo
{
public static void main(String[] args) throws Exception
{
//首先创建流的集合注意这里使用的是ArrayList集合
ArrayList<InputStream> ins = new ArrayList<InputStream>();
ins.add(new FileInputStream("1.txt"));
ins.add(new FileInputStream("2.txt"));
ins.add(new FileInputStream("3.txt"));
//注意这里使用了Collections工具类里面的生成枚举的方法
Enumeration<InputStream> enums = Collections.enumeration(ins);
//实例化序列流对象,注意里面需要一个枚举类型的参数
SequenceInputStream sis = new SequenceInputStream(enums);
//我们构造写入的目的地
FileOutputStream fos = new FileOutputStream("4.txt");
//从源中进行读取写入目的地
//构建自定义的缓冲区
byte[] buffer = new byte[1024];
int len = 0;
while((len = sis.read(buffer)) != -1 ){
fos.write(buffer, 0, len);
}
sis.close();
fos.close();
}
}