Java基础学习 -- I/O系统、流
Java类库里有四个表示流的抽象父类:InputStream、OutputStream、Reader、Writer。
其中 InputStream 和 OutputStream 是对字节进行操作的输入流和输出流;Reader 和 Writer 是对字符操作的输入输出流。
它们是抽象类,在用它们的时候必须要对其进行实例化,因此类库也提供了具有不同功能的它们的子类,比如,以文件形式输入输出的 FileInputStream、FileOutputStream 和FileReader、FileWriter 等。
以下列出了 Java IO 中一些比较常用的流类以及它们的方法使用,更多的流类请查阅API文档。
--------------------------------------------------------------
一、字节流
1. InputStream、OutputStream 只能进行字节的传输数据
InputStream抽象了应用程序读取数据的方式
OutputStream抽象了应用程序写出数据的方式
2. EOF = End,读到 -1 就读到结尾。
3. 输入流的基本方法(以下的 in 代表输入流的对象)
int b = in.read();
从流读取一个字节无符号填充到int的低8位。(一个int变量是4个字节,1字节=8位,read()方法只能读取一个字节并返回int,所以该字节填充到int的低八位。)若读到结尾,返回 -1。用该方法读取大文件时,要使用while循环,这样效率较低,时间也较长,可以使用下面的批量读取方式。
in.read(byte[] buf);
从流读取数据直接填充到字节数组buf,读取字节的个数取决于数组的长度。返回的是读到的字节的个数。如果读到结尾返回-1。
in.read(byte[] buf, int start, int size);
从流读取数据到字节数组buf,从buf的start位置开始,存放最多size长度的数据。返回的是读到的字节的个数。如果读到结尾返回-1。
4. 输出流的基本方法(以下的 out 代表输出流的对象)
out.write(int b);
写出一个byte到流,写出的是b的低8位。
out.write(byte[] buf);
将一个字节数组写出到流。
out.write(byte[] buf, int start, int size);
从buf的start位置开始,写size长度的数据到流。
5. FileInputStream 是 InputStream 的子类,具体实现了在文件上读取字节数据:
package test;import java.io.File; import java.io.FileInputStream; import java.io.InputStream;public class TestDemo {public static void main(String[] args) throws Exception {//我们在D盘下创建了一个demo.txt,内容为“你好hello”。File file = new File("D:\\demo.txt");if(!file.exists()) file.createNewFile();InputStream in = new FileInputStream(file);int temp;while((temp = in.read()) != -1) {System.out.print(Integer.toHexString(temp & 0xff) + " ");}in.close();System.out.println();InputStream in2 = new FileInputStream(file);byte[] buf = new byte[1024];int bytes = in2.read(buf);String s = new String(buf,0,bytes,"GBK");System.out.println(s);in2.close();}} Output: c4 e3 ba c3 68 65 6c 6c 6f 你好hello
6. FileOutputStream 是InputStream的子类,具体实现了在文件上读写出字节数据:
//这是一个拷贝文件的例子 package test;import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException;public class TestDemo {public static void copyFile(File srcFile,File destFile) throws IOException{ if(!srcFile.exists()) {throw new IllegalArgumentException("文件 " + srcFile + " 不存在!");}else if(!srcFile.isFile()) {throw new IllegalArgumentException(srcFile + " 不是文件!");}else {FileInputStream in = new FileInputStream(srcFile);FileOutputStream out = new FileOutputStream(destFile);byte[] bytes = new byte[8*1024];int b;while((b = in.read(bytes, 0, bytes.length)) != -1) {out.write(bytes, 0, b);out.flush(); //对于字节流而言,此句不加也没关系。 }in.close();out.close();} }public static void main(String[] args) {try {copyFile(new File("D:\\demo.txt"),new File("D:\\demo_copy.txt"));} catch (IOException e) {// TODO Auto-generated catch block e.printStackTrace();}}}
7. DataInputStream / DataOutputStream
对“流”功能的扩展,可以更加方便的读写int,long,字符等基本数据类型。
如:DataOutputStream的方法有 writeInt() , writeDouble() , writeUTF() 等。
在构造Data流时,要用到其他的流作为参数。如:DataOutputStream dos = new DataOutputStream(new FileOutputStream(file));
这其实是一种“装饰器(过滤器)”设计模式:首先用“其他的流”来构造Data流,然后像 writeInt() 这些方法里面其实都是用“其他的流”的 write() 方法来实现的,如:一个Int有4个字节,用 write() 八位八位地写,做4次 write() ,然后再做移位操作。说白了就是用 writeInt() 将这些操作包装好,方便以后的直接使用。
writeInt()源码
package test;import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException;public class TestDemo {public static void main(String[] args) throws IOException{ DataOutputStream dos = new DataOutputStream(new FileOutputStream("D:\\demo.dat"));dos.writeInt(10);dos.writeInt(-10);dos.writeUTF("中国"); //采用utf-8编码写出dos.writeChars("中国"); //采用utf-16be编码写出PrintHex.printHex("D:\\demo.dat");dos.close();DataInputStream dis = new DataInputStream(new FileInputStream("D:\\demo.dat"));System.out.println();int i = dis.readInt();System.out.println(i);i = dis.readInt();System.out.println(i);String s = dis.readUTF();System.out.println(s);dis.close();}}/*--------------------------------------------*/ package test;import java.io.FileInputStream; import java.io.IOException;public class PrintHex {public static void printHex(String fileName) throws IOException {FileInputStream in = new FileInputStream(fileName);int b;while((b = in.read()) != -1) {System.out.print(Integer.toHexString(b & 0xff) + " ");}in.close();}}/*** Output:* 0 0 0 a ff ff ff f6 0 6 e4 b8 ad e5 9b bd 4e 2d 56 fd * 10* -10* 中国*/
8. BufferedInputStream / BufferedOutputStream
这两个流类为IO提供了带缓冲区的操作,一般打开文件进行读写操作时都会加上缓冲,这种流模式提高了IO的性能。
从应用程序中把输入放入文件,相当于将一缸水倒入到另一个缸中:
FileOutputStream ---> write() 方法相当于一滴一滴地把水“转移”过去。
DataOutputStream ---> writeXxx() 方法会方便一些,相当于一瓢一瓢把水“转移”过去。
BufferedOutputStream ---> write 方法更方便,相当于一飘一瓢先放入桶中,再从桶中倒入到另一个缸中,性能提高了。
这种字节缓冲流同样是采用装饰模式,要用其他的流来参与构造。
以下是四种不同方式的文件拷贝,效率对比:
package test;import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException;public class CopyMethod {//以单字节传输public static void copyByByte(String srcFile,String destFile) throws IOException {FileInputStream fis = new FileInputStream(srcFile);FileOutputStream fos = new FileOutputStream(destFile);int i;while((i = fis.read()) != -1) {fos.write(i);}fis.close();fos.close();}//以字节数组传输public static void copyByBytes(String srcFile,String destFile) throws IOException {FileInputStream fis = new FileInputStream(srcFile);FileOutputStream fos = new FileOutputStream(destFile);byte[] bytes = new byte[8*1024];int i;while((i = fis.read(bytes, 0, bytes.length)) != -1) {fos.write(bytes, 0, i);}fis.close();fos.close();}//以单字节缓冲流传输public static void copyByByteBuffer(String srcFile,String destFile) throws IOException {BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile));BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFile));int i;while((i = bis.read()) != -1) {bos.write(i);bos.flush(); //缓冲流要冲刷,否则写入不到文件}bis.close();bos.close();}//以字节数组缓冲流传输public static void copyByBytesBuffer(String srcFile,String destFile) throws IOException {BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile));BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFile));byte[] bytes = new byte[8*1024];int i;while((i = bis.read(bytes, 0, bytes.length)) != -1) {bos.write(bytes, 0, i);bos.flush(); //缓冲流要冲刷,否则写入不到文件}bis.close();bos.close();}}
package test;import java.io.IOException;public class TestDemo {public static void main(String[] args) {try { //比较这四种拷贝方式的效率。long start = System.currentTimeMillis();//Copy.copyByByte("D:\\1.mp3", "D:\\2.mp3"); //用时2908ms//Copy.copyByByteBuffer("D:\\1.mp3","D:\\2.mp3"); //用时1854ms//Copy.copyByBytes("D:\\1.mp3","D:\\2.mp3"); //用时7ms//Copy.copyByBytesBuffer("D:\\1.mp3","D:\\2.mp3"); //用时37ms,以字节数组缓冲流的方式反而比不带缓冲的字节数组传输得慢。long end = System.currentTimeMillis();System.out.println(end-start);} catch (IOException e) {// TODO Auto-generated catch block e.printStackTrace();}}}
------------------------------------------------------------------
二、字符流
1) 认识文本和文本文件:
java的文本(char) 是16位无符号整数,是字符的unicode编码(双字节编码)。
文件 是byte byte byte ... 的数据序列。
文本文件 是文本(char)序列按照某种编码方案(utf-8,utf-16be,gbk)序列化为byte的存储结果。
2) 字符流(Reader Writer为抽象类) ---> 一般操作的是文本文件
1. InputStreamReader / OutputStreamWriter
字符的处理:一次处理一个字符。字符的底层依然是基本的字节序列,字符流的基本实现:
InputStreamReader 完成byte流解析为char流,按照编码解析。
OutputStreamWriter 提供char流到byte流,按照编码处理。
字符流在构造时依然要用到字节流对象作为构造参数。
//我们利用字符流同时做了文本文件的打印和拷贝。 package test;import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter;public class IsrAndOswDemo {public static void main(String[] args)throws IOException {FileInputStream in = new FileInputStream("D:\\douban-utf-8.txt");InputStreamReader isr = new InputStreamReader(in,"utf-8"); //如不写编码方式就默认为项目的编码。操作的时候,要写文件本身的编码格式。 FileOutputStream out = new FileOutputStream("D:\\douban-utf-8-copy.txt");OutputStreamWriter osw = new OutputStreamWriter(out,"utf-8");/*int c ;while((c = isr.read())!=-1){System.out.print((char)c);}*/char[] buffer = new char[8*1024];int c;/*批量读取,放入buffer这个字符数组,从第0个位置开始放置,最多放buffer.length个返回的是读到的字符的个数*/while(( c = isr.read(buffer,0,buffer.length))!=-1){String s = new String(buffer,0,c);System.out.print(s);osw.write(buffer,0,c);osw.flush();}isr.close();osw.close();} }
2. FileReader / FileWriter
方便直接读写文本文件,不用像 InputStreamReader 和 OutputStreamWriter 一样需要嵌套一个File字节流。
在构造文件字符流时,有两点需要注意:
1) 不能使用编码方式的参数,也就是说只能读取编码方式和项目编码方式相同的文本文件,否则读取进来再做输出时会乱码。
2) 构造FileWriter时,可以使用append参数,如果设置为true,会在输出的文本文件后面追加文本内容。
//文本文件拷贝实例 package test;import java.io.FileReader; import java.io.FileWriter; import java.io.IOException;public class FrAndFwDemo {public static void main(String[] args) throws IOException{FileReader fr = new FileReader("D:\\douban-gbk.txt");FileWriter fw = new FileWriter("D:\\douban-gbk-copy.txt",true); //可以添加append参数,如果有,则在文件后面追加内容。char[] buffer = new char[2056];int c ;while((c = fr.read(buffer,0,buffer.length))!=-1){fw.write(buffer,0,c);fw.flush();}fr.close();fw.close();} }
3. 字符流的过滤器 BufferedReader / BufferedWriter / PrintWriter
这两个过滤器最强大的功能是具有读写一整行的方法:
BufferedReader ---> readLine() 读一行,但是不能识别换行符
BufferedWriter / PrintWriter ---> 写一行
package test;import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter;public class BrAndBwOrPwDemo {public static void main(String[] args) throws IOException{//对文件进行读写操作 BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("D:\\douban-utf-8.txt"),"utf-8"));/*BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("D:\\douban-utf-8-copy.txt"),"utf-8")); //写出时如果不加编码方式,会按默认的编码方式写出,copy的文件不再是utf-8编码,而是gbk编码。*/PrintWriter pw = new PrintWriter("e:\\javaio\\imooc4.txt","utf-8");//PrintWriter pw1 = new PrintWriter(outputStream,boolean autoFlush); String line ;while((line = br.readLine())!=null) { //readLine方法一次读一行,但并不能识别换行 System.out.println(line);/*bw.write(line);//单独写出换行操作bw.newLine();//换行操作bw.flush();*/pw.println(line); //写入到文件 pw.flush();}br.close();//bw.close(); pw.close();} }
------------------------------------------------------------------
三、对象的序列化和反序列化
对象序列化,就是将 Object 转换成 byte序列,反之叫对象的反序列化。对对象进行序列化和反序列化为的是 方便将来在 网络上 或者 本地 进行对象的传输。
1. 序列化的基本操作 ObjectOutputStream / ObjectInputStream
1) 序列化流(ObjectOutputStream) ---> 方法 writeObject(Object)
反序列化流(ObjectInputStream) ---> 方法 readObject() ,返回的是Object类
2) 序列化接口(Serializable)
要对对象进行序列化,那么这个对象必须要实现序列化接口Serializable,否则将出现异常。这个接口,没有任何方法,只是一个标准。
package test;import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream;public class ObjectSeriaDemo1 {public static void main(String[] args) throws Exception{String file = "demo/obj.dat";//对象的序列化,将stu对象转化为字节序列存入file。ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));Student stu = new Student("10001", "张三", 20);oos.writeObject(stu);oos.flush();oos.close();//对象的反序列化,将file中的字节序列转化为对象。ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));Student stu2 = (Student)ois.readObject(); //需要进行强制类型转换,因为readObject方法返回的是Object类,而不是Student类。 System.out.println(stu2);ois.close();} }
转载于:https://www.cnblogs.com/xingyazhao/p/6005550.html
Java基础学习 -- I/O系统、流相关推荐
- Java基础学习—— IO流
Java基础学习-- IO流 1 文件 1.1 文件的创建 1.2 文件常用的方法 2 IO流 2.1 FileInputStream 2.2 FileOutputStream 2.3 文件的拷贝 2 ...
- java基础学习_IO流03_字符流、IO流小结、案例_day21总结
java基础学习_IO流03_字符流.IO流小结.案例_day21总结 ================================================================ ...
- java基础实现水果超市系统(数组+集合+对象持久化(io流存储到txt文件))
java基础实现水果超市系统(数组+集合+对象持久化(io流存储到txt文件)) Fruit类 package com.zr.fruitSupermarket;/*** 水果* @author ZR* ...
- 尚学堂JAVA基础学习笔记_2/2
尚学堂JAVA基础学习笔记_2/2 文章目录 尚学堂JAVA基础学习笔记_2/2 写在前面 第10章 IO技术 1. IO入门 2. IO的API 3. 装饰流 4. IO实战 5. CommonsI ...
- Java基础学习——第十四章 网络编程
Java基础学习--第十四章 网络编程 一.网络编程概述 计算机网络: 把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规模大.功能强的网络系统,从而使众多的计算机可以方便地互相传递信 ...
- JAVA基础学习精简心得笔记整理
JAVA基础学习精简心得笔记整理 配置java环境变量 Java的运行过程 基本数据类型 引用数据类型 逻辑运算符 数组 方法重载 封装 继承 多态 多态的作用 单例设计模式 接口interface ...
- 【Java基础学习笔记】- Day11 - 第四章 引用类型用法总结
Java基础学习笔记 - Day11 - 第四章 引用类型用法总结 Java基础学习笔记 - Day11 - 第四章 引用类型用法总结 4.1 class作为成员变量 4.2 interface作为成 ...
- java基础学安卓开发_Android开发学习路线之Java基础学习
原标题:Android开发学习路线之Java基础学习 很多Android学习开发者刚入手Android开发技术时,稍微有点迫切.任何的开发技术都有其基础语言,Android应用程序开发是以Java语言 ...
- Java基础学习(9)
Java基础学习 一.常用方法(API) 1.1 Math 1.2 System 1.3 Runtime 1. 4 .object 1.5 Objects 1.6 BigInteger BigInte ...
最新文章
- su oracle : 只切换用户,而不切换环境;就是说切到oracle用户后,使用的依旧是root的环境。 su - oracle :同时切换用户和环境
- php中rsort,php数组函数排序之rsort()
- mysql 中datetime_MySQL中Datetime与Timestamp
- JavaScript编码encode和decode escape和unescape
- Xshell中输入rz提示:-bash: rz: command not found
- JavaScript之BOM基础
- 2019-06-02 Java学习日记之多线程上
- python安装pillow图形处理库
- ios与android设备即时语音互通的录音格式预研说明
- nginx+Git 404 error 错误处理
- 按键精灵手机助手基本教程以及命令-1
- kali linux嗅探图片_kali linux 密码嗅探工具 Dsniff 详解
- 甘超波:NLP五步觉察法
- 秋风:教育部办学还是学校办学?
- 爬虫demo——爬取电影天堂的资源,存储到本地json文件
- java中的传参是什么意思_Java中参数传递是传值还是传址?
- 猿创征文|【实用工具tcping】ping tcping的区别,使用命令,超全超详细使用手册(建议收藏)
- qemu-img命令
- 【MATLAB教程案例16】基于GWO灰狼优化算法的函数极值计算matlab仿真及其他应用
- java socket / IM / Message / chat / liaotian / xmpp
热门文章
- Centos 7 Linux系统修改网卡名称为ethx
- [心得] 如何利用liquibase進行資料庫版本控制 - 實際練習
- HTTPS的七个误解
- 高调coding,低调做人 peakflys P2P的原理和常见的实现方式(为libjingle开路)
- 修改打开方式的程序列表中列出程序的名称
- javascript:URL编解码和父子窗口交互
- MongoDB(window安装及服务配置)
- 斯蒂芬金被退稿_斯蒂芬·金(Stephen King)对技术作家的实用建议
- docker4.9.0.9_Docker支持现实生活中的鲸鱼,通过投票确定Linux v4.0等
- 前端:JS/33/实例:表单验证