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();
- }
- }
Java基础学习 -- I/O系统、流的更多相关文章
- 尚学堂JAVA基础学习笔记
目录 尚学堂JAVA基础学习笔记 写在前面 第1章 JAVA入门 第2章 数据类型和运算符 第3章 控制语句 第4章 Java面向对象基础 1. 面向对象基础 2. 面向对象的内存分析 3. 构造方法 ...
- Java基础学习笔记总结
Java基础学习笔记一 Java介绍 Java基础学习笔记二 Java基础语法之变量.数据类型 Java基础学习笔记三 Java基础语法之流程控制语句.循环 Java基础学习笔记四 Java基础语法之 ...
- 转载-java基础学习汇总
共2页: 1 2 下一页 Java制作证书的工具keytool用法总结 孤傲苍狼 2014-06-24 11:03 阅读:25751 评论:3 Java基础学习总结——Java对象的序列化和 ...
- java基础学习总结——java环境变量配置(转)
只为成功找方法,不为失败找借口! 永不放弃,一切皆有可能!!! java基础学习总结——java环境变量配置 前言 学习java的第一步就要搭建java的学习环境,首先是要安装 JDK,JDK安装好之 ...
- Java基础学习(2)
Java基础学习(二) 面向对象 对象:客观存在的事物 面向对象:人具体关注的事物的某些信息 类:是模子,确定对象会拥有的特征(属性)和行为(方法) 对象的属性:对象具有的各种特征 对象的方法:对象能 ...
- Java基础学习-- 继承 的简单总结
代码参考:Java基础学习小记--多态 为什么要引入继承? 还是做一个媒体库,里面可以放CD,可以放DVD.如果把CD和DVD做成两个没有联系的类的话,那么在管理这个媒体库的时候,要单独做一个添加CD ...
- 2015年12月28日 Java基础系列(六)流
2015年12月28日 Java基础系列(六)流2015年12月28日 Java基础系列(六)流2015年12月28日 Java基础系列(六)流
- Java基础学习中一些词语和语句的使用
在Java基础学习中,我们刚接触Java会遇到一些词和语句的使用不清的情况,不能很清楚的理解它的运行效果会是怎么样的,如:break,continue在程序中运行效果及跳转位置, 1.先来看看brea ...
- java基础学习总结——开篇
java是我学习的第一门编程语言,当初学习java基础的时候下了不少功夫,趁着这段时间找工作之际,好好整理一下以前学习java基础时记录的笔记,当作是对java基础学习的一个总结吧,将每一个java的 ...
随机推荐
- 基于zipkin分布式链路追踪系统预研第一篇
本文为博主原创文章,未经博主允许不得转载. 分布式服务追踪系统起源于Google的论文“Dapper, a Large-Scale Distributed Systems Tracing Infras ...
- fir.im Weekly - 如何进行 Android App 性能优化
关于 Android App 的优化,@anly-jun 用 3 个月完成了这一系列文章,从 性能分析工具 到 ANR .Layout .消除卡顿 到 内存优化.内存分析工具大概十五六篇,并对此做一个 ...
- ES6新特性之 promise
新的ES6中引入了promise的概念,目的是让回调更为优雅.层层嵌套的回调会让javascript失去美感和可读性,同时javascript也推荐采用链式的方式去书写函数调用.于是Promise就应 ...
- SSIS Design3:并发执行
1,利用优先约束来并发处理数据,Data Flow Task 和 Data Flow Task 1 是并发执行的,而 Data Flow Task2 必须等到 Data Flow Task 和 Dat ...
- 数据结构与算法JavaScript (一) 栈
序 数据结构与算法JavaScript这本书算是讲解得比较浅显的,优点就是用javascript语言把常用的数据结构给描述了下,书中很多例子来源于常见的一些面试题目,算是与时俱进,业余看了下就顺便记录 ...
- 【转】C#调用Windows图片和传真查看器打开图片
//建立新的系统进程 System.Diagnostics.Process process = new System.Diagnostics.Process(); //设置文件名,此处为图片的真实路径 ...
- Python第一天 - 迭代
(一)索引迭代 Python中,迭代永远是取出元素本身,而非元素的索引. 如果要取索引可以用enumerate()函数 例: L = ['Adam', 'Lisa', 'Bart', 'Paul'] ...
- DOM操作
DOM操作,JS来操作页面 wiindows对象操作 document对象操作 点击事件:将DIV要执行的事件代码装封 onclick 鼠标单击 ondblelick 鼠标双击 onk ...
- T-SQL:毕业生出门需知系列(目录)
一.前言: 作为一个应届毕业生又要准备面试 ASP.NET 攻城狮了,以前在图书馆觉得这本书讲得挺基础,这次回家就自己买了本用来复习,顺便做下读书笔记. 第4版 二.代码下载: 官方:http://f ...
- 【记录】VS2012新建MVC3/MVC4项目时,报:此模板尝试加载组件程序集“NuGet.VisualStudio.Interop...”
最近电脑装了 VisualStudio "14" CTP,由于把其他版本的 VS 卸掉,由高到低版本安装,当时安装完 VisualStudio "14" CTP ...