1.输入输出流的基本概念
(1).用来处理设备之间的数据传输:包括有内存的数据,硬盘上的文件,以及网络中的数据等;(2).Java对数据的操作时通过流的方式;(3).Java中用于操作流的对象都在java.io包中;(4).流按照操作的数据分类:字节流:包括有图片,视频,音频等;字符流:包括的主要是文本文件;(5).按照流的流向分类:输入流:读;输出流:写;
2.IO流体系
Java.io:|--Reader:字符读取流
|--InputStreamReader:转换流
|--FileReader:文件字符流
|--BufferedReader:带缓冲的加强的字符读取流
|--LineNumberReader:带行标的字符读取流|--PipedReader:管道字符读取流
|--Writer:字符写入流
|--OutputStreamWriter:转换流
|--FileWriter:文件字符流
|--BufferedWriter:带缓冲的加强的字符写入流|--PrintWriter:打印流|--PipedWriter:管道字符写入流
|--InputStream:字节输入流,读取流
|--FileInputStream:文件字节流|--FilterInputStream
|--ObjectInputStream:操作对象的输入流|--BufferedInputStream:带缓冲的加强的字节输入流|--SequenceInputStream:合并流|--PipedInputStream:管道字节输入流
|--OutputStream:字节输出流,写入流
|--FileOutputStream:文件字节流|--FilterOutputStream
|--ObjectOutputStream:操作对象的字节输出流|--BufferedOutputStream:带缓冲的加强的字节输出流|--PrintStream:打印字节流|--PipedOutputStream:管道字节输出流、
IO流中的基类就是InputStream,OutputStream,Reader,Writer,由这些基类派生出来的子类名称都是以其父类名作为子类名的后缀;
在IO流中,类的前缀往往与该流的功能有关;
字符流的底层其实也是以字节为单位来读写数据;
3.字符流
3.1 Reader
(1).Reader中的读取方式:
int read():读取单个字符,返回的是字符的Unicode,如果到达流的末尾则返回-1;阻塞式方法;throws IOException;
int read(char[ ] buf):读取字符到字符数组,返回的是读取的字符数,如果已经到达流的末尾返回-1;阻塞式方法;throws IOException;
abstract void close():抽象的关闭资源方法,具体的实现有子类去实现;
上述方法都有可能会出现IOException;
(2).用来读文件(主要是文本文件)的Reader:FileReader
对构造方法的说明:因为FileReader是用来操作文件的,所以在一初始化时应该关联要操作的文件;
FileReader(File file):参数为文件类型对象;
FileReader(String fileName):参数为文件名;
由于可能关联的文件不存在或者由于什么原因没有关联到,所以该构造方法会抛出:FileNotFoundException;
(3).使用FileReader按照两种方式将指定文件的内容在控制台输出;
/* * 使用FileReader读取指定文件 */ package com.zr.day20; import java.io.*; class FileReaderDemo { public static void main(String[] args) throws IOException { myRead_1(); myRead_2(); } //其中的一些方法在调用时可能会发生异常,所以需要抛异常 public static void myRead_1() throws IOException { //FileReader是用来操作文件的读取流,所以在其初始化时要绑定文件; //在构造方法中可以接受字符型的文件名也可以是封装好的文件类型对象 FileReader fr = new FileReader("demo.txt"); //读取方式一:read();每次读取一个字符; int ch; while((ch=fr.read())!=-1) { System.out.print((char)ch); } //关闭资源 fr.close(); } //带异常处理 public static void myRead_2() { FileReader fr = null; try { fr = new FileReader("demo.txt"); //第二种方式,通过字符数组进行存储 char[] buf = new char[1024]; for(int len;(len = fr.read(buf))!=-1;) { System.out.print(new String(buf,0,len)); } } catch(IOException e) { throw new RuntimeException("读取文件失败"); } finally { //此处判断,避免空指针异常; if(fr!=null) try { fr.close(); } catch(Exception e) { throw new RuntimeException("关闭资源失败"); } } } }
3.2 Writer
(1).Writer中的特有方法:
void write(char[ ] buf):写入字符数组;throws IOException ;
void write(char[ ] buf, int off, int len):写入字符的指定部分;throws IOException ;
void write(int c):写入单个字符;写入的字符包含在给定int值的低16位,高16位被忽略;throws IOException ;
void write(String s):写入字符串;throws IOException ;
abstract void flush():刷新该流的缓冲,刷新到目的文件中,这是Writer体系中的特有方法;
abstract void close():关闭资源操作,关闭之前会刷新流;
上述方法都有可能会出现IOException;
(2).用来写文件的Writer:FileWriter
对构造方法的说明:用来操作文件,所以流对象在初始化时就应该关联具体的文件,也就是明确数据要存放的目的地;
当文件不存在时,会在指定的目录下创建文件,如果文件已经存在可以根据需要设定是否覆盖或者是否在文件末尾继续写入;
IOException:指定文件存在可能是个目录,或者无法创建,或者无法打开;
FileWriter(File file)
FileWriter(File file, boolean append)
FileWriter(String fileName):默认是覆盖已有文件的内容;
FileWriter(String fileName, boolean append):当append字段为true时,会在文件末尾续写;
(3).将某些内容写入到硬盘上的目的文件;
/* * 文件的写操作 */ package com.zr.day20; import java.io.*; class FileWriterDemo { public static void main(String[] args) throws IOException { String str = "在屋顶唱着你的歌"; myWriter(str); } //文件的覆盖写操作 public static void myWriter(String str) { FileWriter fw = null; char[] chs = str.toCharArray(); try { //如果文件不存在会创建文件,然后写入; //如果文件已经存在会覆盖其中的内容; fw = new FileWriter("demo.txt"); fw.write(chs); //刷新 fw.flush(); } catch(IOException e) { throw new RuntimeException("写入操作失败"); } finally { if(fw!=null) try { fw.close(); } catch(Exception e) { throw new RuntimeException("关闭资源失败"); } } } //文件的续写操作 public static void myContinueWriter(String str) throws IOException { //关联某个目的文件,append字段设置为true,表示在文件末尾续写; FileWriter fw = new FileWriter("demo.txt",true); fw.write(str); //刷新操作 fw.flush(); //关闭资源,在关闭之前会刷新 fw.close(); } }
3.3 IO中的异常处理操作
通过复制文本文件来说明;/* * 复制文本文件; * */ package com.zr.day20; import java.io.*; class FileCopyDemo { public static void main(String[] args) { //定义输入流,用来读取源文件; FileReader fr = null; //定义输出流,用来写入目的文件; FileWriter fw = null; try { fr = new FileReader("demo.txt"); fw = new FileWriter("copydemo.txt"); //也可以读一个写一个; /* for(int ch; (ch=fr.read())!=-1;) { fw.write(ch); fw.flush(); } */ //定义字符数组; char[] buf = new char[1024]; for(int len; (len=fr.read(buf))!=-1;) { fw.write(buf,0,len); fw.flush(); } } catch(IOException e) { throw new RuntimeException("复制文件失败"); } finally //对于资源的关闭要分别处理; { if(fr!=null) try { fr.close(); } catch(Exception e) { throw new RuntimeException("关闭资源失败"); } if(fw!=null) try { fw.close(); } catch(Exception e) { throw new RuntimeException("关闭资源失败"); } } } }
3.4 字符流缓冲区:BufferedReader
BufferedReader的出现是为了提高字符流的读取效率;
(1).构造方法:有参的构造方法,需要提高字符读取流的效率,在初始化的时候就必须要关联某个读取流Reader;
BufferedReader(Reader in):创建一个使用默认大小的缓冲区来缓冲字符输入流,关联某个读输入流;
(2).BufferedReader的缓冲技术原理是使用数组缓冲;
(3).特有的读取方法:String readLine(),读取一个文本行,不包含任何行终止符,如果已经到达流的末尾,返回null;
原理是遇到换行或者回车标记,不论是读取一行还是读取多个字符,其实都是一个字符一个字符的读取,底层使用的还是Reader中的read()方法;
由此可以看出装饰类的设计原理:利用原有的方法功能,提供更加强大的方法;
(4).使用字符缓冲区复制文件;