黑马程序员_IO流

 
 
------------- android培训java培训、java博客、java学习型技术博客、期待与您交流! -------------

IO流

概述 java对数据的操作都是通过流的方式,而操作流的对象都封装在IO包中。 凡是和设备发生数据关系的,几乎都有IOExcpetion。 流的分类 按数据流向不同可分为:输入流和输出流; 按处理数据不同可分为:字节流和字符流; 字节流一次读入或读出是一个字节即8位二进制, 字符流一次读入或读出是一个字符即16位二进制(默认GBK解编码)。 按实现功能不同可分为:节点流和处理流。 节点流:能直接与数据源相连,实现读写; 处理流:需与节点流一块使用,作用是增强节点流功能,实现更快更准确的读写。(装饰设计模式类) 一览 字符输入流(Reader) 字符输出流(Writer) |--节点流类型 |--节点流类型 |--FileReader |--FileWriter |--PipedReader |--PipedWriter |--CharArrayReader |--CharArrayWriter |--处理流类型 |--处理流类型 |--BufferedReader |--BufferedWriter |--InputStreamReader |--OutputStreamWriter |--PrintWriter 字节输入流(InputStream) 字节输出流(OutputStream) |--节点流类型 |--节点流类型 |--FileInputStream |--FileOutputStream |--PipedInputStream |--PipedOutputStream |--ByteArrayInputStream |--ByteArrayOutputStream |--处理流类型 |--处理流类型 |--BufferedInputStream |--BufferedOutputStream |--DataInputStream |--DataOutputStream |--ObjectInputStream |--ObjectOutputStream |--SequenceInputStream |--PrintStream 介绍 Writer(写入字符流的抽象类) 方法 1、写入   write(int c) 写入单个字符,c为指定要写入字符的int, 写入的字符包含在给定整数值的16个低位中,另16高位被自动忽略   write(char[] cbuf) 写入字符数组   write(char[] cbuf,int off,int len) 写入字符数组的某一部分   write(String str) 写入字符串   write(String str,int off ,int len) 写入字符串的某一部分 2、刷新   flush() 刷新该流的缓冲,写入字符流类通常需要刷新数据到目的地 3、关闭   close() 关闭此流,但会先刷新它,另关闭的是与底层系统的链接并不是关闭对象 Reader(读取字符流的抽象类) 方法 1、读取   int read()  读取单个字符,返回该字符的int,若读到该留末尾,则为-1。   int read(char[] cbuf)     cbuf为目标缓冲区,返回的int为读取的字符数,若到该流末尾,则为-1。 2、关闭   close() InputStreamReader/OutputStreamWriter(转换流) 前者是字节流通向字符流的桥梁,可使用指定字符集读取字节并将其解码为字符; 后者是字符流通向字节流的桥梁,可使用指定字符集将要写入流中的字符编码成字节。 构造方法 InputStreamReader(InputStream in) 默认GBK码表 InputStreamReader(InputStream in,String charsetName) OutputStreamWriter(OutputStream out) 默认GBK码表 OutputStreamWriter(OutputStream out,String charsetName) 子类 FileReader 、 FileWriter FileReader/FileWriter(字符文件读取|写入流) 写入/读取字符文件的便捷类 构造方法 字符读取/写入流对象一建立,就需要明确操作的文件 FileReader(File file) |  FileReader(String fileName) FileWriter(File file) |  FileWriter(String fileName) 对于后者,若文件不存在则会新建一个文件,若存在则会直接覆盖,如想续写,则写成: FileWriter(File file,true) |  FileWriter(String fileName,true) BufferedReader/BufferedWriter(字符读取|写入缓冲流) 前者从字符输入流中读取文本,缓冲各个字符,从而实现高效读取; 后者将文本写入字符输出流,缓冲各个字符,从而提供高效写入。 原理 该流内部封装数组缓冲区,将所读字符\或所写字符先存入数组,在一次读出或写入数组中字符 构造方法 BufferedReader(Reader in) | BufferedWriter(Writer out) 特有方法 String readLine() 读取一个文本行,通过'\r'和'\n'确认该行终止  返回包含该行内容的字符串,但不包含任何行终止符,若已到末尾,则返回null newLine() 因为读取一行方法不带行终止符,所以每写一行数据需要自动加行分隔符,  另该方法可跨平台性使用。 BufferedReader 子类 LineNumberReader 该缓冲字符输入流,提供了setLineNumber和getLineNumber两种方法,即可以带行号的输出数据 原理:内部封装了int型lineNumber,每调用一次readLine方法,该值增1。 InputStream/OutputStream(字节输入输出流) 方法 1、读取   int read() 从流中读取下一个字节,返回0-255内的int字节值,若到末尾则为-1;   int read(byte[] b) 读取一定数量字节并存储进缓冲区数组b中,  返回的int,为读取的字节数,若到末尾则返回-1. 2、写入   write(byte[] b) 将byte数组中元素全部写入输出流   write(byte[] b,int off,int len), 将byte数组部分元素写入输出流中   write(int b) 将指定的字节写入此输出流,写入的的字节为b的八个低位 另:字节流的写入可不用刷新。 3、关闭 close() FileInputStream/FileOutputStream(字节文件输入输出流) 与字符文件输入输出流类似 BufferedInputStream/BufferedOutputStream(字节输入输出缓冲流) 功能类似字符输入输出缓冲流,但没有上述特有方法 PrintStream/PrintWriter(打印输出/写入流) 为其他输出流添加了功能,使它们能够方便打印各种数据值表示形式。 特有功能 1、该流内部对IO异常进行了处理,永远不会抛出IOException 2、提供的打印方法,可以将各种类型数据都原样打印,同时可指定编码 3、可自动刷新,可调用println方法以自动换行 4、JDK1.5版本后,直接操作文件, 构造方法 PrintWriter(File file) || PrintWriter(String fileName)   直接操作文件 PrintWriter(OutputStream out) 创建不带自动行刷新 PrintWriter(OutputStream out,boolean autoFlush) 创建带自动行刷新, 如果为true,则println、printf、format方法会自动刷新 PrintStream 构造方法与上述一样,但PrintWriter多了接受Writer流的构造方法 PrintWriter(Writer,out,boolean autoFlush) 应用 异常日志信息,可通过该流输入到文件,步骤: 创建PrintStream并管理异常日志, catch数理代码中,调用printStackTrace(PrintStream ps) PipedInputStream/PipedOutputStream(字节管道流) PipedReader/PipedWriter(字符管道流) IO中涉及多线程技术的流 概述 将管道输出流与管道输入流连接以创建通信管道; 输出流可往管道中写入数据,输入流可从管道中读取数据; 因为输入和输出是同时进行,所以需用一个线程输出,一个线程输入。 构造方法 PipedOutputStream() 创建为连接到管道输入流的管道输出流 这样构造,需要用到连接方法 connect(PipedInputStream snk)将它们连接 PipedOutputStream(PipedInputStream snk) 连接snk的管道输出流 字节输入管道流类似,字符管道流同理。 ByteArrayInputStream/ByteArrayOutputStream(操作字节数组流) CharArrayReader/CharArrayWriter(操作字符数组流) 概述 操作的数据,为数组中数据,该数据存储位置是在内存中; 内部封装了数组,作为缓冲区,没有调用底层资源,不会抛出IO异常; 用流的思想操作数组。 构造方法 ByteArrayInputStream(byte[] buf)/ByteArrayInputStream(byte[] buf,int offset,int len) CharArrayReader(char[] buf)/CharArrayReader(char[] buf ,int offset,int length) 其读取数据都为数组,且各自内部包含一个内部缓冲区,该缓冲区包含从流中读取的字节, 内部计数器跟踪read方法要提供的下一个字节; 从构造函数可以看出读取的是数组中数据,不用调用底层read,且不会抛异常,并不用关闭; ByteArrayOutputStream() CharArrayWriter() 构造函数不用指定数据目的,因为它们内部封装了一个可变长度数组,调用write方法会将 数据写入数组中,且会随着数据的不断增长而自动增长,可使用toByteArray()|toCharArray() 和toString()获取数据 特有方法 writeTo(OutputStream out)  |  writeTo(Writer out) 将数组输出流的全部内容写入到指定的输出流参数中 toString() | toString(String charsetName) 可使用指定charsetName,解码字节将缓冲区内容转换为字符串 DataInputStream/DataOutputStream(数据输入输出流) 概述 专门用来操作基本数据类型的流; 数据输出流可将Java基本数据类型数据局写入输出流中; 数据输入流可从底层输入流中读取Java基本数据类型数据; 不过输出的数据格式与读取数据的格式要一致,否则读不出来。 构造方法 DataInputStream(InputStream in) | DataOutputStream(OutputStream out) ObjectInputStream/ObjectOutputStream(对象操作流) 概述 后者可以将Java对象的基本数据类型和图形写入该流中,称为对象的序列化; 前者可将后者写入的基本数据和对象进行反序列化; 对象在程序运行时,是存储于堆内存的,随着程序结束,该对象也消失了, 所以可借助两者与字节文件输入输出流一起使用来实现对象的持久存储; 另被操作的对象必须是实现了Serializable接口的对象。 构造方法 ObjectInputStream(InputStream in) ObjectOutputStream(OutputStream out) 读取/写入对象方法 Object readObject() 从InputStream流中读取对象 writeObject(Object obj) 将对象写入到OutputStream流中 注意 静态成员不能被序列化,因为其不再堆内存中; 使用transient关键字可使非静态的数据不被序列化 SequenceInputStream(序列流) 概述 它表示其它输入流的逻辑串联,所涉及输入流用有序集合进行封装, 它从第一个输入流开始,依次读取到最后一个输入流末尾为止; 它实现了多个数据的合并。 构造方法 两个流的连接 SequenceInputStream(InputStream s1,InputStream s2) 多个流的连接 SequenceInputStream(Enumeration<? extends InputStream> e) 参数必须是运行生成类型为InputStream对象的Enumeration型参数 参数 Enumeration<? extends InputStream e> 1、用Vector封装流对象,然后通过elments()方法获取该接口对象; 2、用ArrayList封装流对象,后建立Enumeration匿名内部类用迭代器中的 hasNext()和Next()方法分别复写枚举接口中的hasMoreElements()和nextElement() 示例 ArrayList<InputStream> al = new ArrayList<InputStream>(); Iterator<InputStream> it = al.iterator(); SequenceInputStream sis = new SequenceInputStream(new Enumeration<InputStream>() { public boolean hasMoreElements() { return it.hasNext(); } public InputStream nextElement() { return it.next(); } }); RandomAccessFile(随机访问文件) 概述 该类不算是IO体系中子类,而是直接继承自Object,但是它是IO包中成员,因为它具备读和写功能 内部封装了一个数组,而且通过指针对数组的元素进行操作 可以通过getFilePointer获取指针位置,同时可以通过seek改变指针的位置   其实完成读写的原理就是内部封装了字节输入和输出流 构造方法 RandomAccessFile(File file,String mode) RandomAccessFile(String name,String mode) 通过构造函数可以看出该类只能操作文件 而且操作文件还有模式,r、rw、rws、rwd四种模式 如果模式为r,不会创建文件,会去读取一个已存在文件,如果该文件不存在则会出现异常 如果模式为rw,操作的文件不存在,则自动创建,如果存在则不会覆盖 方法 随机访问文件,自身具备读写的方法,通过skipBytes(int x)、seek(int x)来达到随机访问 注意skipBytes()方法指正不能往回跳; 流输入输出数据都是从头到尾开始按照顺序执行, 但是该类可以自定义读取位置,也可以指定位置添加写入值,所以就可以实现数据的分段写入, 从而可以为每段数据分配一个线程进行写入,如多个线程下载数据模式就是这个道理。

源和目的

概述 IO流中对象操作的是数据,数据的来源及数据去向分为以下几种; 源:  内存、硬盘和键盘 目的:内存,硬盘和控制台 内存 临时数据,如操作字节或字符数组流操作的数组对象就是存储在内存中。 键盘和控制台 控制台即将数据输出至屏幕:  InputStream in = System.in; 键盘即通过键盘来录入数据; PrintStream out = System.out; 硬盘 持久化存储的数据,一般以File形式存在,因为流只能操作数据, Java中File类将文件或文件夹封装成对象,以方便操作这些对象。 File 构造方法 File(String pathName) File(String parent,String child) File(File parent,String child) 方法 1、创建 boolean createNewFile() 在指定位置创建文件,如果该文件已经存在,则不创建,返回false 和输出流不一样,输出流对象一建立就创建文件,而且若文件已经存在则会覆盖 boolean mkdir() 创建文件夹,只能创建一级文件夹 boolean mkdirs() 创建多级文件夹 2、删除 boolean delete() 删除失败返回false void deleteOnExit() 在程序退出时删除指定文件 3、判断 boolean exists() 文件是否存在 isFile() 判断是否文件 isDirectory() 判断是否为文件目录 isHiden()   判断文件是否隐藏文件 isAboslute() 判断文件路径是否是绝对路径名 4、获取 String getName() 返回文件名 String getPath() 返回文件路径,构建时候指定的是什么返回什么 String getParent() 返回父目录的路径名字,若没指定,则返回null String getAbsoultePath()  返回文件绝对路径 long lastModified()  返回最后一次被修改的时间 long length();    返回文件大小,以字节为单位 5、重要方法 String[] list(); 返回一个字符串数组,它为目录中的文件和目录 String[] list(FilenameFilter filter) 返回满足指定过滤器的文件和目录的字符串数组 File[] listFiles() 返回抽象路径名数组 File[] listFiles(FilenameFilter filter) 返回满足指定过滤器的文件和目录的抽象路径名数组 一般用后者,因为返回的File[]还可被File对象方法操作。 FilenameFilter 接口,可用于过滤某些文件名,接口方法只有: boolean accept(File dir,String name) dir 文件目录 name 文件名称 返回true就保留,返回假就舍弃,e.g new FilenameFilter(){ public boolean accept(File dir,String name){ return name.endsWith(".java"); } } dir中文件名不是以.java结尾的文件会被过滤掉

其他相关类

System 方法 InputStream in = System.in; PrintStream out = System.out; static void setIn(InputStream in) 重新分配"标准"输入流 static void setOut(OutputStream out) 重新分配"标准"输出流 Properties extends HashTable<Object,Object> 概述 该类表示了一个持久的属性集,可保存在流中或从流中加载; 它的属性列表中每个键及其对应值都是一个字符串,因而不需要泛型; 它可以加载流直接读取键盘中文件里的键值对信息,而且还可以修改键值对匹配值且保存在原有文件中; 它是集合中与IO技术相结合的集合容器。 方法 1、添加键值对, Object setProperty(String key,String value) 调用HashTable的put方法,强制添加的键值为字符串,返回为指定键的旧址,若没有则null 2、读取 String getProperty(String key) 获取该键的值,若没有则为null Set<String> stringPropetryNames() 返回属性列表中键集 Enumeration<?> propertyNames() 返回属性列表中键的枚举 3、加载字节流(1.2版本)、加载字符流(1.6版本) load(InputStream in) 从输入流中读取属性列表 load(Reader r) 按简单的面向行的格式从字符读取流中读取属性列表 4、写入字节流(1.2版本)、写入字符流(1.6版本) Store(OutputStream out,String comments)  将适合格式将属性列表写入输出流 Store(Writer wrieter,String comments)  以适合格式将属性裂隙写入输出流   comments 代表注释

其它

装饰设计模式 当想要对已有的对象进行功能增强时,可定义类,将已有对象传入,基于已有的功能,并提供加强功能,该类就称为装饰类 装饰类通常会通过构造方法接受被装饰对象,并基于被装饰的对象的功能,提供更强的功能; IO中处理流基本都是运用装饰设计模式产生的类。见如下自定缓冲字符读取流示例 class MyBufferedReader extends Reader { private Reader r ; MyBufferedReader(Reader r){ this.r = r; } public String readLine()throws IOException{ StringBuilder sb = new StringBuilder(); int ch = 0; while((ch=r.read())!=-1){ if (ch=='\r') continue; else if(ch=='\n') return sb.toString(); else sb.append((char)ch); } if(sb.length()!=0) return sb.toString(); return null; } public void close() throws IOException{ r.close(); } public int read(char[] cbuf,int off,int len)throws IOException{ return r.read(cbuf,off,len); } } 递归 其实就是函数自身内部调用自身方法。 递归就是在栈内存中不断的加载同一个函数。 应用 当一个功能被重复使用,而每一次使用该功能时的参数不确定,都由上次的功能元素结果来确定。 功能内部又用到该功能,但是传递的参数值不确定。(每次功能参与运算的未知内容不确定)。 注意事项 1:一定要定义递归的条件; 2:递归的次数不要过多,容易出现 StackOverflowError 栈内存溢出错误。 示例 将毕向东java基础文件夹中文件夹+文件名的相对路径名写入当前java.txt中 import java.io.*; class Demo5 { public static void main(String[] args){ for (int x=1;x<26 ;x++ ){ File dir = new File("c:\\java\\毕向东Java基础\\第"+x+"天"); method(dir); } } public static void method(File dir){ BufferedWriter bfw = null; try{ bfw = new BufferedWriter(new FileWriter("java.txt",true)); bfw.write(dir.getName()); bfw.newLine(); File[] files = dir.listFiles(); for (int x=0;x<files.length;x++){ if (files[x].isDirectory()) method(files[x]); //此处递归 else{ bfw.write("  "+files[x].getName()); bfw.flush(); bfw.newLine(); } } } catch (IOException e1){ throw new RuntimeException("failed to write"); } finally{ try { if(bfw!=null) bfw.close(); } catch (IOException e2) {} } } }
------------- android培训 java培训 、java博客、java学习型技术博客、期待与您交流! -------------
详情请查看:http://edu.csdn.net/heima/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值