Java知识:IO流
来源:互联网 发布:电脑监控软件价格 编辑:程序博客网 时间:2024/05/17 09:15
Java中IO流的体系结构如图:
Java流类的类结构图:
主要的类如下:
1. File(文件特征与管理):用于文件或者目录的描述信息,例如生成新目录,修改文件名,删除文件,判断文件所在路径等。 2. InputStream(二进制格式操作):***抽象类***,基于字节的输入操作,是所有输入流的父类。定义了所有输入流都具有的共同特征。 3. OutputStream(二进制格式操作):***抽象类***。基于字节的输出操作。是所有输出流的父类。定义了所有输出流都具有的共同特征。 4.Reader(文件格式操作):***抽象类***,基于字符的输入操作。 5. Writer(文件格式操作):***抽象类***,基于字符的输出操作。 6. RandomAccessFile(随机文件操作):一个独立的类,直接继承至Object.它的功能丰富,可以从文件的任意位置进行存取(输入输出)操作。
接下来结合例子理解各个IO流
FileInputStream
/** * 字节流 *读文件 * */import java.io.*;class hello{ public static void main(String[] args) throws IOException { String fileName="D:"+File.separator+"hello.txt"; File f=new File(fileName); InputStream in=new FileInputStream(f); byte[] b=new byte[1024]; int count =0; int temp=0; while((temp=in.read())!=(-1)){ b[count++]=(byte)temp; } in.close(); System.out.println(new String(b)); }}
DataOutputStream与DataInputStream
import java.io.DataOutputStream ; import java.io.File ; import java.io.FileOutputStream ; public class DataOutputStreamDemo{ public static void main(String args[]) throws Exception{ // 所有异常抛出 DataOutputStream dos = null ; // 声明数据输出流对象 File f = new File("d:" + File.separator + "order.txt") ; // 文件的保存路径 dos = new DataOutputStream(new FileOutputStream(f)) ; // 实例化数据输出流对象 String names[] = {"衬衣","手套","围巾"} ; // 商品名称 float prices[] = {98.3f,30.3f,50.5f} ; // 商品价格 int nums[] = {3,2,1} ; // 商品数量 for(int i=0;i<names.length;i++){ // 循环输出 dos.writeChars(names[i]) ; // 写入字符串 dos.writeChar('\t') ; // 写入分隔符 dos.writeFloat(prices[i]) ; // 写入价格 dos.writeChar('\t') ; // 写入分隔符 dos.writeInt(nums[i]) ; // 写入数量 dos.writeChar('\n') ; // 换行 } dos.close() ; // 关闭输出流 } };
import java.io.DataInputStream ; import java.io.File ; import java.io.FileInputStream ; public class DataInputStreamDemo{ public static void main(String args[]) throws Exception{ // 所有异常抛出 DataInputStream dis = null ; // 声明数据输入流对象 File f = new File("d:" + File.separator + "order.txt") ; // 文件的保存路径 dis = new DataInputStream(new FileInputStream(f)) ; // 实例化数据输入流对象 String name = null ; // 接收名称 float price = 0.0f ; // 接收价格 int num = 0 ; // 接收数量 char temp[] = null ; // 接收商品名称 int len = 0 ; // 保存读取数据的个数 char c = 0 ; // '\u0000' try{ for(int i=0;i<3;i++){ //如果是while(true)是会产生EOFException的!!!! temp = new char[200] ; // 开辟空间 len = 0 ; while((c=dis.readChar())!='\t'){ // 接收内容 temp[len] = c ; len ++ ; // 读取长度加1 } name = new String(temp,0,len) ; // 将字符数组变为String price = dis.readFloat() ; // 读取价格 dis.readChar() ; // 读取\t num = dis.readInt() ; // 读取int dis.readChar() ; // 读取\n System.out.printf("名称:%s;价格:%5.2f;数量:%d\n",name,price,num) ; } }catch(Exception e){e.printStackTrace;} //原作者没有写e.printStackTrace;这句话 dis.close() ; } };
经过这个例子会对这个类有所理解,下面这两句话对理解这个类很有帮助:
DataInputStream是数据输入流,可以读取java的基本数据类型。
FileInputStream是从文件系统中,读取的单位只能是字节。
ByteArrayInputStream+PushBackInputStream
/** * 回退流操作 * */public class PushBackInputStreamDemo{ public static void main(String[] args) throwsIOException{ public static void main(String[] args) throws Exception { String s="123456789"; byte b[]=s.getBytes(); BufferedInputStream bis=new BufferedInputStream(new ByteArrayInputStream(b)); PushbackInputStream pis=new PushbackInputStream(bis); int tmp=1; int i=0; while((tmp=pis.read())!=-1) { if(tmp=='3') //监听 { pis.unread('n'); //修改 tmp=pis.read(); //修改后的值保存到变量tmp } System.out.print((char)tmp); i++; } pis.close(); } }}
ByteArrayInputStream基本的介质流之一,它从Byte数组中读取数据。
FIleInputStream也是基本的介质流之一,它从文件中读取数据。
PushBackInputStream的作用:监听流中的数据,如果监听到自己感兴趣的数据可以对其进行改写。
InputStream与BufferedInputStream比较
public class DataInputStreamDemo { private static final String FILENAME="E:\\迅雷下载\\越狱.Prison.Break.S05E06.中英字幕.HDTVrip.720P.mp4"; public static void main(String[] args) throws IOException { long l1 = readByBufferedInputStream(); long l2 = readByInputStream(); System.out.println("通过BufferedInputStream读取用时:"+l1+";通过InputStream读取用时:"+l2); // System.out.println("通过BufferedInputStream读取用时:"+l1); } public static long readByInputStream() throws IOException { InputStream in=new FileInputStream(FILENAME); byte[] b=new byte[8192]; int l=0; long start=System.currentTimeMillis(); while(in.read(b)!=-1){ } long end=System.currentTimeMillis(); return end-start; } public static long readByBufferedInputStream() throws IOException { BufferedInputStream in=new BufferedInputStream(new FileInputStream(FILENAME)); byte[] b=new byte[8192]; int l=0; long start=System.currentTimeMillis(); while(in.read(b)!=-1){ } long end=System.currentTimeMillis(); return end-start; } }
上面的程序我们再多测试几种情况:
两个new byte[8192]的情况下:
通过BufferedInputStream读取用时:325;通过InputStream读取用时:320
两个new byte[4096]的情况下:
通过BufferedInputStream读取用时:356;通过InputStream读取用时:501
两个new byte[1024]的情况下:
通过BufferedInputStream读取用时:355;通过InputStream读取用时:1467
两个new byte[512]的情况下:
通过BufferedInputStream读取用时:370;通过InputStream读取用时:2847
两个new byte[256]的情况下:
通过BufferedInputStream读取用时:374;通过InputStream读取用时:5457
我们发现BufferedInputStream的优势显现出来了,快了10多倍。
疑问1:为什么BufferedInputStream读取时间没什么变化?
其实明确一点:读取数据的快慢和程序访问磁盘的次数(IO操作)是有极大关系的,可以说是主要影响因素。
BufferedInputStream自身维护了一个默认8192字节(8K)的缓冲区,这个缓冲区有什么用呢?
如果一份文件8M,那么程序访问了8M/8=1000次
new byte[8192],new byte[4096],new byte[1024],new byte[512],new byte[256]是程序自己维护的数组,数来存储缓冲区数据,8K缓冲区仍然没有改变,那么访问磁盘次数没变,所以时间大体上是相同的。
也可以说是此例子中的BufferedInputStream类自身维护了一个8K缓冲区,程序员又为他提供了一个new Byte数组来记录缓冲区中的数据。8K的缓冲区不变,读取时间不会有很大变化。
疑问2:为什么FileInputStream读取时间变化那么大?
FileInputStream没有缓冲区,我们是通过创建一个New Byte数组来模拟缓冲区。
new byte[8192],new byte[4096],new byte[1024],new byte[512],new byte[256]不同的byte数组会使得访问磁盘次数产生很大变化,进而影响读取时间,所以时间变化大而且细心的会发现呈现指数变化。
疑问2:为什么8K的时候BufferedInputStream比FIleInputStream速度还慢?
两个类都有8K缓冲区:
BufferedInputStream类自身维护的8K缓冲区
我们为FileInputStream模拟的8Kbyte数组
所以他们访问磁盘的次数相同,但是BufferedInputStream不是单纯的维护一个数组,还要维护数组中其他“东西”(我也不想弄清楚有啥)所以他的操作慢一些。
关键是弄明白两个new byte的作用!
BufferedInputStream中的new byte[]是存储缓冲区中的数据,属于内存操作,速度快,对读取时间影响小
FileInputStream中的new byte[]起到的是缓冲区的作用,属于IO操作,速度慢,对读取时间影响大。
FileInputStream与FileOutputStream复制MP3的例子来唤醒对这两个类的记忆
FileInputStream fis = new FileInputStream("c:\\0.mp3"); FileOutputStream fos = new FileOutputStream("c:\\1.mp3");byte[] buf=new byte[1024];int len=0;while((len=fis.read())!=-1){ fos.write(buf,0,len);}fos.close();fis.close();
BufferedInputStream与BufferedOutputStream复制MP3来唤醒对这两个类的记忆
FileInputStream fis = new FileInputStream("c:\\0.mp3"); BufferedInputStream bis=new BufferedInputStream(fis);FileOutputStream fos = new FileOutputStream("c:\\1.mp3");BufferedOutputStream bos=new BufferedOutputStream(fos);byte[] buf=new byte[1024]; //这句话对效率的提升也有很大帮助,不光需要BufferedInputStream、BufferedOutputStream的内部缓冲区来提升效率。int len=0;while((len=fis.read())!=-1){ fos.write(buf,0,len);}fos.close();fis.close();
ByteArrayInputStream与ByteArrayOutputStream:使用内存操作流将一个大写字母转化为小写字母
/** * 使用内存操作流将一个大写字母转化为小写字母 * */import java.io.*;class hello{ public static void main(String[] args) throws IOException { String str="ROLLENHOLT"; ByteArrayInputStream input=new ByteArrayInputStream(str.getBytes()); ByteArrayOutputStream output=new ByteArrayOutputStream(); int temp=0; while((temp=input.read())!=-1){ char ch=(char)temp; output.write(Character.toLowerCase(ch)); } String outStr=output.toString(); input.close(); output.close(); System.out.println(outStr); }}
PipedInputStream+PipedOutputStream实现线程间通讯
public class DataInputStreamDemo { //private static final String FILENAME="E:\\迅雷下载\\越狱.Prison.Break.S05E06.中英字幕.HDTVrip.720P.mp4"; public static void main(String[] args) throws IOException { PipedInputStream input=new PipedInputStream(); PipedOutputStream output=new PipedOutputStream(); input.connect(output); new Thread(new Input(input)).start(); new Thread(new Output(output)).start(); }}class Input implements Runnable{ private PipedInputStream in; Input(PipedInputStream in) { this.in=in; } @Override public void run() { // TODO Auto-generated method stub try { byte[] b=new byte[1024]; int len=in.read(b); String s=new String(b,0,len); System.out.println("s="+s); in.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }} class Output implements Runnable { private PipedOutputStream out; Output(PipedOutputStream out) { this.out=out; } @Override public void run() { // TODO Auto-generated method stub try { //Thread.sleep(5000); out.write("hi.管道来了".getBytes()); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }}
控制台输出:
s=hi.管道来了
此流不建议用于单线程,可能会引起死锁。因为read方法是阻塞式方法,在单线程中读取不到数据会一直等待,write方法执行不到。
FileReader与FileWriter例程
public class Test{ private static final int BUFFER_SIZE=1024; public static void main() { FileReader fr=null; FileWriter fw=null; try { fr=new FileReader("1.txt"); fw=new FileWriter("2.txt"); //创建一个临时容器,用于缓存读取到的字符 char[] buf=new char[BUFFER_SIZE];//这就是缓冲区 //定义一个变量记录读取到的字符数,(其实就是往数组里装的字符个数) int len=0; while((len=fr.read(buf))!=-1) { fw.write(buf,0,len); } }catch(Exception e) { throw new RuntimeException("读写失败"); }finally { if(fw!=null) try { fw.close(); }catch(Exception) { e.printStackTrace(); } if(fr!=null) try { fr.close(); }catch(Exception) { e.printStackTrace(); } } }}
BufferedReader与BufferedWriter例程
public class test{ public static void main() { FileReader fr=new FileReader("1.txt"); BufferedReader bufr=new BufferedReader(fr); FileWriter fw=new FileWriter("2.txt"); BufferedWriter bufw=new BufferedWriter(fw); String line=null; while((line=bufr.readLine())!=null) { bufw.write(line); bufw.newLine(); bufw.flush(); } bufr.close(); bufw.close(); }}
转换流:InputStreamReader与OutputStreamWriter例程:控制台输入字符串,控制台显示字符串
public class test{ public static void mian(String[] args)throws IOException { //控制台输入 InputStream in=System.in; //通过转换流转换成字符数据,方便操作 InputStreamReader isr=new InputStreamReader(in); //加入缓冲更高效 BufferedReader bufr=new BufferedReader(isr); OutputStream out=System.out; OutputSteamWriter osw=new OutputStream(out); BufferedWriter bufw=new BufferedWriter(osw); String line=null; while((line=bufr.readLine())!=null) { if("over".equals(line)) break; bufw.write(line.toupperCase()); bufw.newLine(); bufw.flush(); } }}
不使用转换流也可以完成上述功能,本例子就是为了加深转换流的印象才用的转换流。
什么情况下必须用转换流呢?
当需要明确码表的时候
public static void main(String[] args) throws IOException { //在IO流中,如果想指定编码读写数据,只能使用转换流。 //采用指定编码从文本文件中读取内容 BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("C:\\a.txt"), "UTF-8")); String line = null; while ((line=br.readLine())!=null) { System.out.println(line); } br.close(); }
public static void main(String[] args) throws IOException { BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("C:\\a.txt"), "UTF-8")); bw.write("I am 。。"); bw.close(); }
IO流操作规律
想要知道开发时用到哪个对象。只要通过四个明确即可。
1、明确源和目的
源:InputStream Reader
目的:OutputStream Writer
2、明确数据是否是纯文本。
源:是纯文本:Reader
否:InputStream
目的:是纯文本:Writer
否:OutputStream
3、明确具体的设备:
源设备:
硬盘:File
键盘:System.in
内存:数组
网络:Socket流
目的设备:
硬盘:File
键盘:System.in
内存:数组
网络:Socket流
4、是否需要额外功能
1、是否需要高效(缓冲区)
是就加上buffer
2、转换
需求1:复制一个文本文件
1、明确源和目的:
源:InputStream Reader
目的:OutputStream Writer
2、是否是纯文本?
是
源:Reader
目的:Writer
3、明确具体设备
源:
硬盘:File
目的;
硬盘:File
FileReader fr=new FileReader(“1.txt”);
FileWriter fw=new FileWriter(“2.txt”);
4、需要额外功能吗?
需要:高效
BufferedReader bufr=new BufferedReader(new FileReader(“1.txt”));
BufferedWriter bufw=new BufferedWriter(new FileWriter(“2.txt”));
需求2:读取键盘录入信息,并写入到一个文件中。
1、明确源和目的。
源:InputStream Reader
目的:OutputStream writer
2、是否是纯文本呢?
是
源:Reader
目的:Writer
3、明确具体设备
源:
键盘:System.in
目的;
硬盘:File
InputStream in=System.in;
FileWriter fw=new FileWriter(“1.txt”);
4、是否需要额外功能?
是:需要转换
InputStreamWriter isw=new InputStreamWriter(System.in);
FileWriter fw=new FileWriter(“1.txt”);
还需要功能吗?需要高效
BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in))
BufferedWriter bufw=new BufferedWriter(new FileWriter(“1.txt”));
需求3:将一个文本文件数据显示在控制台上。
1、明确源和目的。
源:InputStream Reader
目的:OutputStream writer
2、是否是纯文本呢?
是
源:Reader
目的:Writer
3、明确具体设备
源:
硬盘:File
目的;
显示器:System.out
FileReader fr=new FileReaderr(“1.txt”);
OutputStream os=System.out;
4、需要额外功能吗?
需要,转换
FileReader fr=new FileReader(“1.txt”);
OutputStreamWriter osw=new OutputStreamWriter(System.out);
需要,高效
BufferedReader bufr=new BufferedReader(new FileReader(“1.txt”));
BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(System.out));
需求4:读取键盘录入数据,显示在控制台上。
1、明确源和目的。
源:InputStream Reader
目的:OutputStream writer
2、是否是纯文本呢?
是
源:Reader
目的:Writer
3、明确具体设备
源:
键盘:System.in
目的;
显示器:System.out
InputStream in=System.in;
OutputStream out=System.out;
4、明确额外功能
需要转换:
InputStreamReader isr=new InputStreamReader(System.in);
OutputStreamWriter osw=new OutputStreamWriter(System.out);
为了将其高效。
BufferedReader bufr=new BufferedReader(new InputStreamReaer(System.in));
BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(System.out));
需求5:将一个中文字符串按照指定的编码表写入到一个文本文件
1、明确源和目的。
源:无
目的:OutputStream writer
2、是否是纯文本呢?
是
源:无
目的:Writer
3、明确具体设备
源:
无
目的;
硬盘:File
FileWriter fw=new FileWriter(“1.txt”);
4、需要额外功能吗?
需要转换
注意:既然需求明确了制定编码表的动作那就不可以使用FileWriter,因为FileWriter内部是使用默认的本地码表。只能使用其父类OutputStreamWriter,OutputStreamWriter接受一个字节输出流对象,既然是操作文件,那么应该是FileOutputStream
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream(“1.txt”),charset);
需要高效吗?
需要
BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream(“1.txt”),charset))
Java IO所采用的模型
还需要详解一下
Java的IO模型设计非常优秀,它使用Decorator(装饰者)模式,按功能划分Stream,您可以动态装配这些Stream,以便获得您需要的功能。
例如,您需要一个具有缓冲的文件输入流,则应当组合使用FileInputStream和BufferedInputStream。
参考资料:
http://blog.csdn.net/tanqian351/article/details/51209438
https://www.2cto.com/kf/201312/262036.html
http://blog.csdn.net/jiangwei0910410003/article/details/22376895
http://blog.csdn.net/u013087513/article/details/52148934
http://bbs.csdn.net/topics/390517474/
http://blog.csdn.net/u013905744/article/details/51924258
毕向东Java讲义 PDF版
- Java知识:IO流
- Java IO流知识总结
- Java IO流相关知识
- Java IO流知识总结
- java知识--IO流详解
- java-IO流相关知识
- Java IO流相关知识
- 【Java】Java 中IO流知识总结
- Java中的IO流知识总结
- Java中的IO流知识总结 【转】
- Java中的IO流知识总结
- Java中的IO流知识总结
- Java知识总结-IO字符流
- Java知识总结-IO字节流
- Java中的IO流知识总结
- 【JAVA知识】IO流(1)
- java 中IO 流的知识
- java语言中IO流知识
- 2017/0910 实验结果记录
- 灰度图像形态学膨胀与腐蚀
- jquery 函数返回参数
- HDFS1.0 与HDFS2.x 架构理解
- Linux文件保护
- Java知识:IO流
- Linux远程连接ssh时提示:IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
- Activity的生命周期
- dubbo管理控制台安装和使用
- spark mongodb
- DBSCAN聚类
- 【安全牛学习笔记】w3af-身份认证
- ConcurrentHashMap 总结( 下 )
- 关于移动端响应式全屏背景图显示的问题