文件在网络上或不同设备之间是怎么传输的,在Java程序中又是怎么来实现文件的传输,带着这两个问题,来了解一下Java中的IO流相关类及操作。

一、什么是流及流的用途

  流是一组有顺序,有起点和终点的字节的集合,是对数据传输的总称和抽象。简单说流就是在不同设备之间进行数据传输。流的本质是数据传输,JDK为了方便开发者操作流,根据数据传输的各种特性,将流抽象为多种类,从而更加方便直观的操作。

二、流的分类

  根据处理的数据类型的不同,可将IO流分为字节流和字符流;根据IO流的流向又可将其分为输入流和输出流。一般来说,如果没有指出按什么分类,IO流的分类默认按处理数据的类型分为:字符输入流、字符输出流、字节输入流及字节输出流。

三、字符流和字节流的区别

  字符流的由来: 因为数据编码不同,而有了对字符进行高效操作的流对象。字符流本质是基于字节流读取,并查询指定的码表。

l  读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。

l  处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。

结论:只要是处理纯文本数据,优先考虑使用字符流。 除此之外都使用字节流。

四、 输入流和输出流

  输入和输出相对于内存而言,输入读入内存,输出从内存输出。对输入流只能进行读操作,对输出流只能进行写操作。

五、 流对象

 1) 字符输入流   Reader

  1. Reader 是所有的输入字符流的父类,它是一个抽象类;
  2. CharReader、StringReader 是两种基本的介质流,它们分别将Char 数组、String中读取数据。PipedReader 是从与其它线程共用的管道中读取数据;
  3. BufferedReader 很明显就是一个装饰器,它和其子类负责装饰其它Reader 对象;
  4. FilterReader 是所有自定义具体装饰流的父类,其子类PushbackReader 对Reader 对象进行装饰,会增加一个行号;
  5. InputStreamReader 是一个连接字节流和字符流的桥梁,它将字节流转变为字符流。FileReader 可以说是一个达到此功能、常用的工具类,在其源代码中明显使用了将FileInputStream 转变为Reader 的方法。我们可以从这个类中得到一定的技巧。Reader 中各个类的用途和使用方法基本和InputStream 中的类使用一致。后面会有Reader 与InputStream 的对应关系。

 2)字符输出流   Writer

  1. Writer 是所有的输出字符流的父类,它是一个抽象类;
  2. CharArrayWriter、StringWriter 是两种基本的介质流,它们分别向Char 数组、String 中写入数据。PipedWriter 是向与其它线程共用的管道中写入数据;
  3. BufferedWriter 是一个装饰器为Writer 提供缓冲功能;
  4. PrintWriter 和PrintStream 极其类似,功能和使用也非常相似;
  5. OutputStreamWriter 是OutputStream 到Writer 转换的桥梁,它的子类FileWriter 其实就是一个实现此功能的具体类(具体可以研究一SourceCode)。功能和使用和OutputStream 极其类似,后面会有它们的对应图。

 3)字节输入流   InputStream

  1. InputStream 是所有的输入字节流的父类,它是一个抽象类;
  2. ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三种基本的介质流,它们分别从Byte 数组、StringBuffer、和本地文件中读取数据。PipedInputStream 是从与其它线程共用的管道中读取数据,与Piped 相关的知识后续单独介绍;
  3. ObjectInputStream 和所有FilterInputStream 的子类都是装饰流(装饰器模式的主角)。

 4)字节输出流   OutputStream

  1. OutputStream 是所有的输出字节流的父类,它是一个抽象类;
  2. ByteArrayOutputStream、FileOutputStream 是两种基本的介质流,它们分别向Byte 数组、和本地文件中写入数据。PipedOutputStream 是向与其它线程共用的管道中写入数据;
  3. ObjectOutputStream 和所有FilterOutputStream 的子类都是装饰流。

六、转换流

 

1)具体实现对象类

  1. InputStreamReader        字节到字符的桥梁
  2. OutputStreamWriter       字符到字节的桥梁

注意:这两个流对象是字符体系中的成员,本身是字符流,所以在构造的时候需要传入字节流对象。

 2)特点:

  1. 字符流和字节流之间的桥梁
  2. 可对读取到的字节数据经过指定编码转换成字符
  3. 可对读取到的字符数据经过指定编码转换成字节

 3)什么时候使用转换流

  1. 当字节和字符之间有转换动作时;
  2. 流操作的数据需要编码或解码时。

七、File

  File类是对文件系统中文件以及文件夹进行封装的对象,可以通过面向对象的思想来操作文件和文件夹。 File类保存文件或目录的各种元数据信息,包括文件名、文件长度、最后修改时间、是否可读、获取当前文件的路径名,判断指定文件是否存在、获得当前目录中的文件列表,创建、删除文件和目录等方法。

八、RandomAccessFile

  该对象并不是流体系中的一员,其封装了字节流,同时还封装了一个缓冲区(字符数组),通过内部的指针来操作字符数组中的数据。 该对象特点:
 1)该对象只能操作文件,所以构造函数接收两种类型的参数:a.字符串文件路径;b.File对象。
 2)该对象既可以对文件进行读操作,也能进行写操作,在进行对象实例化时可指定操作模式(r,rw)
  注意:该对象在实例化时,如果要操作的文件不存在,会自动创建;如果文件存在,写数据未指定位置,会从头开始写,即覆盖原有的内容。 可以用于多线程下载或多个线程同时写数据到文件。
  看完了上面的总结,不知道亲是否对IO流的操作有个整体的印象,接下来还是通过代码来体现一下面向对象的思想吧。

package cn.dolphin.io;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
//import java.io.PrintWriter; /**
* Java中IO操作的演示
*
* @author Cyanide
* @version v1.0.0
* @since v1.0.0
*
*/
public class FileDemo {
public static void main(String[] args) throws IOException {
// createFile();
// copyText1();
// copyText2();
// copyText3();
// copyText4();
// copyText5();
// copyBinary1();
// copyBinary2();
// copyBinary3();
//copyBinary4();
//codec();
printFlow();
} // -------------------------------------------------//
// 基本类输入输出流对象及高效缓冲流对象 //
// -------------------------------------------------//
/**
* File类的文件目录创建及删除操作演示
*
* @throws IOException
*/
static void createFile() throws IOException {
File f1 = new File("file.txt");
File f2 = new File("directory");
// 在当前项目目录中创建文件,需要处理异常。
f1.createNewFile();
// 在当前项目目录中创建目录
f2.mkdir();
// 删除创建的目录的文件
f1.delete();
f2.delete();
} /**
* 文本文件的复制操作,基本实现,每读一个字符写一次。
*
* @throws IOException
*/
static void copyText1() throws IOException {
// 创建FileReader对象,抛出FileNotFoundException。
FileReader fileReader = new FileReader("file.txt");
// 创建FileWriter对象,抛出IOException。
FileWriter fileWriter = new FileWriter("copies.txt");
int num = 0;// fileReader.read()读到文件末尾返回-1。
while ((num = fileReader.read()) != -1) {
fileWriter.write(num);
}
fileWriter.close();
fileReader.close();
// 点评:效率低下,因此会采用第二种方式进行拷皮。
} /**
* 文本文件的复制操作,每读1024个字符写一次。
*
* @throws IOException
*/
static void copyText2() throws IOException {
FileReader fileReader = new FileReader("file.txt");
FileWriter fileWriter = new FileWriter("copies.txt");
// length每次读出字符的实际长度
int length = 0;
char[] chs = new char[1024];
while ((length = fileReader.read(chs)) != -1) {
// 注意:fileReader.read()将读到的字符存入数组,如果最后
// 一次读到字符长度不足字符数组长度时,未覆盖索引处字符也会
// 读出,因此指定 length,读多少,写多少。
fileWriter.write(chs, 0, length);
}
fileWriter.close();
fileWriter.close();
// 点评:效率比copyText1()高出很多,但还有更好的。
} /**
* 文本文件的复制操作,高效缓存读写,每次一个字符。
*
* @throws IOException
*/
static void copyText3() throws IOException {
BufferedReader bufferedReader = new BufferedReader(new FileReader(
"file.txt"));
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(
"copies.txt"));
int num = 0;
while ((num = bufferedReader.read()) != -1) {
bufferedWriter.write(num);
}
bufferedWriter.close();
bufferedReader.close();
} /**
* 文本文件的复制操作,高效缓存读写,每次读1024个字符。
*
* @throws IOException
*/
static void copyText4() throws IOException {
BufferedReader bufferedReader = new BufferedReader(new FileReader(
"file.txt"));
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(
"copies.txt"));
int length = 0;
char[] chs = new char[1024];
while ((length = bufferedReader.read(chs)) != -1) {
bufferedWriter.write(chs, 0, length);
}
bufferedWriter.close();
bufferedReader.close();
} /**
* 文本文件的复制操作,高效缓存读写,每次读一行,特有方法读写。
*
* @throws IOException
*/
static void copyText5() throws IOException {
BufferedReader bufferedReader = new BufferedReader(new FileReader(
"file.txt"));
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(
"copies.txt"));
String str = null;
while ((str = bufferedReader.readLine()) != null) {
bufferedWriter.write(str);
// readLine()方法读取不带换行,所以需要写入换行。
bufferedWriter.newLine();
bufferedWriter.flush();
}
bufferedWriter.close();
bufferedReader.close();
} /**
* 二进制文件的复制操作,基本实现,每读一个字节写一次。
*
* @throws IOException
*/
static void copyBinary1() throws IOException {
FileInputStream fileInputStream = new FileInputStream("file.bmp");
FileOutputStream fileOutputStream = new FileOutputStream("copies.bmp");
int num = 0;
while ((num = fileInputStream.read()) != -1) {
fileOutputStream.write(num);
}
fileInputStream.close();
fileOutputStream.close();
} /**
* 二进制文件的复制操作,每读1024个字节写一次。
*
* @throws IOException
*/
static void copyBinary2() throws IOException {
FileInputStream fileInputStream = new FileInputStream("file.bmp");
FileOutputStream fileOutputStream = new FileOutputStream("copies.bmp");
int length = 0;
byte[] bytes = new byte[1024];
while ((length = fileInputStream.read(bytes)) != -1) {
fileOutputStream.write(bytes, 0, length);
}
fileInputStream.close();
fileOutputStream.close();
} /**
* 二进制文件的复制操作,高效缓存读写,每次一个字节。
*
* @throws IOException
*/
static void copyBinary3() throws IOException {
BufferedInputStream bufferedInputStream = new BufferedInputStream(
new FileInputStream("file.bmp"));
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(
new FileOutputStream("copies.bmp"));
int num = 0;
while ((num = bufferedInputStream.read()) != -1) {
bufferedOutputStream.write(num);
}
bufferedOutputStream.close();
bufferedInputStream.close();
} /**
* 二进制文件的复制操作,高效缓存读写,每次读1024个字节。
*
* @throws IOException
*/
static void copyBinary4() throws IOException {
BufferedInputStream bufferedInputStream = new BufferedInputStream(
new FileInputStream("file.bmp"));
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(
new FileOutputStream("copies.bmp"));
int length = 0;
byte[] bytes = new byte[1024];
while ((length = bufferedInputStream.read(bytes)) != -1) {
bufferedOutputStream.write(bytes, 0, length);
}
bufferedInputStream.close();
bufferedOutputStream.close();
} // -------------------------------------------------//
// 缓冲高效转换流对象 //
// -------------------------------------------------//
/**
* 高效缓冲流结合转换流对文本进行复制编码及解码过程。
* @throws IOException
*/
static void codec() throws IOException {
//编码过程,将文本文件中编码。
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(new FileInputStream("file.txt"), "gb2312"));
//解码过程,将解码后的流写入文本文件。
//BufferedWriter bufferedWriter = new BufferedWriter(
//new OutputStreamWriter(new FileOutputStream("copies.txt"),"gb2312"));
//将键盘录入内容编码
//System.out.print("输入测试文本内容:");
//BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in,"gb2312"));
//将解码后的流直接输出到Console。
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(System.out,"utf-8"));
int length = 0;
char[] chs = new char[1024];
while ((length = bufferedReader.read(chs))!=-1) {
bufferedWriter.write(chs,0,length);
}
bufferedWriter.close();
bufferedReader.close();
//总结:用什么编码,就用什么解码。 如果编码和解码不一致,如果上例就会出现乱码显示。
} static void printFlow() throws IOException{
BufferedReader bufferedReader = new BufferedReader(new FileReader("file.txt"));
//将流写入文本。
//PrintWriter printWriter = new PrintWriter(new FileWriter("copies.txt"),true);
//将流输出到Console。
PrintStream printStream = new PrintStream(System.out);
char[] chs = new char[1024];
while (bufferedReader.read(chs)!=-1) {
printStream.println(chs);
//printWriter.println(chs);
bufferedReader.read(chs);
}
bufferedReader.close();
printStream.close();
}
}

  最后PrintStream及PrintWriter只是输出,没有相应的输入。想想Java开始的第一天那个HelloWorld就用到了PrintStream只是刚开始不明白罢了。或许现在了还有不明白的地方,但随着知识的积累,相信学习Java会是件很快乐的事。

最新文章

  1. Atitit.自然语言处理--摘要算法---圣经章节旧约39卷概览bible overview v2 qa1.docx
  2. cocos2dx 3.x(让精灵随着重力感应的方向移动而移动)
  3. ECshop后台角色权限的添加和分配
  4. linux计划任务
  5. 自动备份SQL数据库 并删除指定日期之前的备份文件
  6. NodeMCU初探
  7. [mysql] Some non-transactional changed tables couldn't be rolled back
  8. 在centos下部署docker内网私服
  9. [LeetCode] Combination Sum II (递归)
  10. 玩转HTML5移动页面
  11. Netsharp FAQ
  12. The 5th Zhejiang Provincial Collegiate Programming Contest---ProblemE:Easy Task
  13. css background-position (图片裁取)
  14. SpringAop进行日志管理。
  15. Unity3D NGUI事件监听的综合管理
  16. 应届生求职:IT博客真能当技术型职位的求职利器?
  17. servlet的请求转发与重定向
  18. 40. 数据泵导入导出impdp、expdp
  19. Appium+Python3+ Android入门
  20. Linux命令(十一) 显示文件类型 file

热门文章

  1. shell文本过滤编程(一):grep和正則表達式
  2. hdu 4544 湫湫系列故事——消灭兔子 优先队列+贪心
  3. javase复习
  4. libLAS1.8.0 编译和配置(VS2013+Win7 64)(一)
  5. Javascript防冒泡事件与Event对象
  6. iOS:简单使用UIAlertVIew和UIActionSheet
  7. m_Orchestrate learning system---十四、数据表中字段命名规则
  8. CreateProcess
  9. Python之Linux下的virtualenv
  10. C# WindowsAPI