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系统、流的更多相关文章

  1. 尚学堂JAVA基础学习笔记

    目录 尚学堂JAVA基础学习笔记 写在前面 第1章 JAVA入门 第2章 数据类型和运算符 第3章 控制语句 第4章 Java面向对象基础 1. 面向对象基础 2. 面向对象的内存分析 3. 构造方法 ...

  2. Java基础学习笔记总结

    Java基础学习笔记一 Java介绍 Java基础学习笔记二 Java基础语法之变量.数据类型 Java基础学习笔记三 Java基础语法之流程控制语句.循环 Java基础学习笔记四 Java基础语法之 ...

  3. 转载-java基础学习汇总

    共2页: 1 2 下一页  Java制作证书的工具keytool用法总结 孤傲苍狼 2014-06-24 11:03 阅读:25751 评论:3     Java基础学习总结——Java对象的序列化和 ...

  4. java基础学习总结——java环境变量配置(转)

    只为成功找方法,不为失败找借口! 永不放弃,一切皆有可能!!! java基础学习总结——java环境变量配置 前言 学习java的第一步就要搭建java的学习环境,首先是要安装 JDK,JDK安装好之 ...

  5. Java基础学习(2)

    Java基础学习(二) 面向对象 对象:客观存在的事物 面向对象:人具体关注的事物的某些信息 类:是模子,确定对象会拥有的特征(属性)和行为(方法) 对象的属性:对象具有的各种特征 对象的方法:对象能 ...

  6. Java基础学习-- 继承 的简单总结

    代码参考:Java基础学习小记--多态 为什么要引入继承? 还是做一个媒体库,里面可以放CD,可以放DVD.如果把CD和DVD做成两个没有联系的类的话,那么在管理这个媒体库的时候,要单独做一个添加CD ...

  7. 2015年12月28日 Java基础系列(六)流

    2015年12月28日 Java基础系列(六)流2015年12月28日 Java基础系列(六)流2015年12月28日 Java基础系列(六)流

  8. Java基础学习中一些词语和语句的使用

    在Java基础学习中,我们刚接触Java会遇到一些词和语句的使用不清的情况,不能很清楚的理解它的运行效果会是怎么样的,如:break,continue在程序中运行效果及跳转位置, 1.先来看看brea ...

  9. java基础学习总结——开篇

    java是我学习的第一门编程语言,当初学习java基础的时候下了不少功夫,趁着这段时间找工作之际,好好整理一下以前学习java基础时记录的笔记,当作是对java基础学习的一个总结吧,将每一个java的 ...

随机推荐

  1. Spark的持久化简记

    摘要: 1.spark 提供的持久化方法 2.Spark的持久化级别 3.如何选择一种最合适的持久化策略 内容: 1.spark 提供的持久化方法 如果要对一个RDD进行持久化,只要对这个RDD调用c ...

  2. C#中日期记忆日期的格式化,日期格式化说明

    参数format格式详细用法:格式字符 关联属性/说明 d ShortDatePattern D LongDatePattern f 完整日期和时间(长日期和短时间) F FullDateTimePa ...

  3. Sql Server系列:Transact-SQL概述

    结构化查询语言(Structure Query Language,SQL)是对数据库进行查询和修改的语言.Transact-SQL是SQL的一种实现形式,它包含了标准的SQL语言部分. 根据完成的具体 ...

  4. Cnblogs支持Latex及测试

    为了方便后续机器学习文章的书写,因此在cnblogs中设置了支持Latex. 设置: 在"后台管理"中"页首Html代码"中加入如下代码: <script ...

  5. 深入理解DOM事件类型系列第一篇——鼠标事件

    × 目录 [1]类型 [2]顺序 [3]坐标位置[4]修改键[5]相关元素[6]鼠标按键[7]滚轮事件[8]移动设备 前面的话 鼠标事件是web开发中最常用的一类事件,毕竟鼠标是最主要的定位设备.本文 ...

  6. .NET平台开源项目速览(5)深入使用与扩展SharpConfig组件

    上个月在文章:这些.NET开源项目你知道吗?让.NET开源来得更加猛烈些吧  和 .NET平台开源项目速览(1)SharpConfig配置文件读写组件 中都提到了SharpConfig组件,简单轻量级 ...

  7. WebService中使用Aspose.Cells.dll

    首先,目前我是在Json里面使用的,然后关于HTML+WebService+Json怎么使用,可以看看Jsonp跨域的相关例子. 本次的实现原理是:通过HTML传送参数到WebService,然后在W ...

  8. CSS三种写法的优先级

    在HTML文件中引入CSS样式有三种方法: 外部样式:通过link标签引入CSS样式: 内页样式:写在HTML页面里面的style标签里面: 行内样式:写在对应标签的style属性里面. 我知道一般情 ...

  9. Color Transfer between Images code实现

    上计算机视觉课老师布置的作业实现论文:Color Transfer between Images 基本思路是: 1.给定srcImg和targetImg 2.将RGB空间转为Lab空间 3.根据论文中 ...

  10. 9.Struts2在Action中获取request-session-application对象

    为避免与Servlet API耦合在一起,方便Action类做单元测试. Struts2对HttpServletRequest.HttpSession.ServletContext进行了封装,构造了三 ...