IO流(小试牛刀)——Java
IO流
下面是关于IO流常用的类或接口:
Java 流的所有类和接口的结构图:
流的作用与概念
流是一组有顺序的、有起点和终点的字节集合,它是对数据传输的总称或抽象。流的本质就是数据传输,根据数据传输的特质将流抽象为各种类,方便更加直观的便捷的对数据进行处理与操作。
IO流的分类
- 根据不同的数据类型分类:字符流与字节流。
- 根据不同的传输方向分类:输入流与输出流。
字符流和字节流
字节流和字符流的区别:
- 读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
- 处理对象不同:字节流能处理所有类型的数据(如图片、avi等流文件对象),而字符流只能处理字符类型的数据。
字符流的由来: 因为数据编码的不同,而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表。
结论:只要是处理纯文本数据,就优先考虑使用字符流。 除此之外都使用字节流。
输入流和输出流
对输入流只能进行读操作,对输出流只能进行写操作,程序中需要根据待传输数据的不同特性而使用不同的操作流。
File类
在学习IO流前我们必须需要了解FIle类:
文件和目录路径名的抽象表示形式。
File类是对文件系统中文件以及文件夹进行封装的对象,可以通过对象的思想来操作文件和文件夹。 File类保存文件或目录的各种元数据信息,包括文件名、文件长度、最后修改时间、是否可读、获取当前文件的路径名,判断指定文件是否存在、获得当前目录中的文件列表,创建、删除文件和目录等方法。
package csdn;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 代码演示
* @author
*
*/
public class JTest {
public static void main(String[] args) {
File file = new File("D:/新建文件夹");// 创建File类 ‘/’与‘\\’具有同样的效应,但不能混合使用
try {
if (!file.exists()) {//判断该文件是否存在
file.mkdirs();//创建文件夹
}
file.delete();//删除文件或目录,必须保证该目录下为空
file = new File("D:/新建文件夹/stu.txt");//重新创建文件
file.createNewFile();//创建新文件
File[] f = file.listFiles();// 获取该文件目录下的所有文件路径(仅包含自己的子级,不包含孙子级)
if (f != null) {// 判断是否为空,避免空指针异常
for (File fi : f) {// 遍历整个数组
System.out.println(fi);//输出打印所有的文件路径到控制台
}
}
System.out.println("是否是一个目录?" + file.isDirectory());// 判断该文件对象的是否为目录文件夹对象?
System.out.println("是否是一个文件?" + file.isFile());// 判断该文件对象是否为一个文件对象?
System.out.println("绝对路径:" + file.getAbsolutePath());// 获取该文件对象的绝对路径
System.out.println("文件夹名字:" + file.getName());// 输出文件对象的名字
System.out.println("该文件的路径:" + file.toString());// 输出文件对象
System.out.println("该文件对象的内容长度:" + file.length());// 输出文件对象的长度
{// 打印该文件的对象的最后修改时间
long t = file.lastModified();// 获取文件对象的最后修改日期
Date date = new Date(t);// 创建时间对象
SimpleDateFormat time = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");// 创建时间格式化对象
System.out.println("该文件对象最后的修改日期:" + time.format(date));// 输出文件对象最后修改日期的指定时间格式。
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class FireWriterDemo {
public static void main(String[] args) throws IOException { //需要对IO异常进行处理
//创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件。
//而且该文件会被创建到指定目录下。如果该目录有同名文件,那么该文件将被覆盖。
FileWriter fw = new FileWriter("F:\\1.txt");//目的是明确数据要存放的目的地。
//调用write的方法将字符串写到流中
fw.write("hello world!");
//刷新流对象缓冲中的数据,将数据刷到目的地中
fw.flush();
//关闭流资源,但是关闭之前会刷新一次内部缓冲中的数据。当我们结束输入时候,必须close();
fw.write("first_test");
fw.close();
//flush和close的区别:flush刷新后可以继续输入,close刷新后不能继续输入。
}
}
要求:用单个字符和字符数组进行分别读取
- class FileReaderDemo { //FileReader的reade()方法.
- public static void main(String[] args) {
- characters();
- }
- /*****************字符数组进行读取*********************/
- private static void characters() {
- try {
- FileReader fr = new FileReader("Demo.txt");
- char [] buf = new char[6];
- //将Denmo中的文件读取到buf数组中。
- int num = 0;
- while((num = fr.read(buf))!=-1) {
- //String(char[] value , int offest,int count) 分配一个新的String,包含从offest开始的count个字符
- sop(new String(buf,0,num));
- }
- sop('\n');
- fr.close();
- }
- catch (IOException e) {
- sop(e.toString());
- }
- }
- /*****************单个字母读取*************************/
- private static void singleReader() {
- try {
- //创建一个文件读取流对象,和指定名称的文件关联。
- //要保证文件已经存在,否则会发生异常:FileNotFoundException
- FileReader fr = new FileReader("Demo.txt");
- //如何调用读取流对象的read方法?
- //read()方法,一次读取一个字符,并且自动往下读。如果到达末尾则返回-1
- int ch = 0;
- while ((ch=fr.read())!=-1) {
- sop((char)ch);
- }
- sop('\n');
- fr.close();
- /*int ch = fr.read();
- sop("ch=" + (char)ch);
- int ch2 = fr.read();
- sop("ch2=" + (char)ch2);
- //使用结束注意关闭流
- fr.close(); */
- }
- catch (IOException e) {
- sop(e.toString());
- }
- }
- /**********************Println************************/
- private static void sop(Object obj) {
- System.out.print(obj);
- }
- }
File类中的其他属性与方法就不在这儿一一列举了。
RandomAccessFile类
该对象并不是流体系中的一员,其封装了字节流,同时还封装了一个缓冲区(字符数组),通过内部的指针来操作字符数组中的数据。 该对象特点:
- 该对象只能操作文件,所以构造函数接收两种类型的参数:a.字符串文件路径;b.File对象。
- 该对象既可以对文件进行读操作,也能进行写操作,在进行对象实例化时可指定操作模式(r,rw)
注意:该对象在实例化时,如果要操作的文件不存在,会自动创建;如果文件存在,写数据未指定位置,会从头开始写,即覆盖原有的内容。 可以用于多线程下载或多个线程同时写数据到文件。
下面切入正题:
JavaIO流对象
一、字节流
字节流的继承图:
1.输入字节流InputStream
IO输入字节流的继承图可见上图,可以看出:
- InputStream 是所有的输入字节流的父类,它是一个抽象类(不可以实例化)。
- ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三种基本的介质流,它们分别从Byte 数组、StringBuffer、和本地文件中读取数据。PipedInputStream 是从与其它线程共用的管道中读取数据。
- ObjectInputStream (对象流)和所有FilterInputStream(过滤流) 的子类都是装饰流(装饰器模式的主角),在后边介绍。
2.输出字节流OutputStream
- OutputStream 是所有的输出字节流的父类,它是一个抽象类(不能实例化)。
- ByteArrayOutputStream、FileOutputStream 是两种基本的介质流,它们分别向Byte 数组、和本地文件中写入数据。PipedOutputStream 是向与其它线程共用的管道中写入数据,
- ObjectOutputStream(对象流) 和所有FilterOutputStream(过滤流) 的子类都是装饰流,后边介绍。
3.字节流的输入与输出的对应
- 图中蓝色的为主要的对应部分,红色的部分就是不对应部分。紫色的虚线部分代表这些流一般要搭配使用。从上面的图中可以看出Java IO 中的字节流是极其对称的。“存在及合理”我们看看这些字节流中不太对称的几个类吧!
- PrintStream 也可以认为是一个辅助工具。主要可以向其他输出流,或者FileInputStream 写入数据,本身内部实现还是带缓冲的。本质上是对其它流的综合运用的一个工具而已。一样可以踢出IO 包!System.out 和System.out 就是PrintStream 的实例!
二、字符流
字符的输入输出对应关系图:
1.字符输入流Reader
在上面的继承关系图中可以看出:
- Reader 是所有的输入字符流的父类,它是一个抽象类(不能实例化)。
- CharReader、StringReader 是两种基本的介质流,它们分别将Char 数组、String中读取数据。PipedReader 是从与其它线程共用的管道中读取数据。
- BufferedReader (设置缓冲区)很明显就是一个装饰器,它和其子类负责装饰其它Reader 对象。
- FilterReader (设置过滤)是所有自定义具体装饰流的父类,其子类PushbackReader 对Reader 对象进行装饰,会增加一个行号。
- InputStreamReader(转换流) 是一个连接字节流和字符流的桥梁,它将字节流转变为字符流。FileReader 可以说是一个达到此功能、常用的工具类,在其源代码中明显使用了将FileInputStream 转变为Reader 的方法。我们可以从这个类中得到一定的技巧。Reader 中各个类的用途和使用方法基本和InputStream 中的类使用一致。后面会有Reader 与InputStream 的对应关系。
缓冲输出流实例:
- import java.io.*;
- class BufferedReaderDemo {
- public static void main(String[] args) throws IOException {
- //创建一个字符读取流流对象,和文件关联
- FileReader rw = new FileReader("buf.txt");
- //只要将需要被提高效率的流作为参数传递给缓冲区的构造函数即可
- BufferedReader brw = new BufferedReader(rw);
- for(;;) {
- String s = brw.readLine();
- if(s==null) break;
- System.out.println(s);
- }
- brw.close();//关闭输入流对象
- }
- }
2.字符输出流Writer
在上面的继承关系图中可以看出:
- Writer 是所有的输出字符流的父类,它是一个抽象类(不能实例化)。
- CharArrayWriter、StringWriter 是两种基本的介质流,它们分别向Char 数组、String 中写入数据。PipedWriter 是向与其它线程共用的管道中写入数据,
- BufferedWriter(设置缓冲区) 是一个装饰器为Writer 提供缓冲功能。
- PrintWriter 和PrintStream 极其类似,功能和使用也非常相似(平时使用都不做具体区分)。
- OutputStreamWriter 是OutputStream 到Writer 转换的桥梁,它的子类FileWriter 其实就是一个实现此功能的具体类(具体可以研究一SourceCode)。功能和使用和OutputStream 极其类似,后面会有它们的对应图。
字符输入流实例:
- import java.io.*;
- class BufferedWriterDemo {
- public static void main(String[] args) throws IOException {
- //创建一个字符写入流对象
- FileWriter fw = new FileWriter("buf.txt");
- //为了提高字符写入效率,加入了缓冲技术。
- //只要将需要被提高效率的流作为参数传递给缓冲区的构造函数即可
- BufferedWriter bfw = new BufferedWriter(fw);
- //bfw.write("abc\r\nde");
- //bfw.newLine(); 这行代码等价于bfw.write("\r\n"),相当于一个跨平台的换行符
- //用到缓冲区就必须要刷新
- for(int x = 1; x < 5; x++) {
- bfw.write("abc");
- bfw.newLine(); //java提供了一个跨平台的换行符newLine();
- bfw.flush();
- }
- bfw.flush(); //刷新缓冲区
- bfw.close(); //关闭缓冲区,但是必须要先刷新
- //注意,关闭缓冲区就是在关闭缓冲中的流对象
- fw.close(); //关闭输入流对象
- }
- }
三、字符流与字节流转换
转换流的特点:
- 其是字符流和字节流之间的桥梁
- 可对读取到的字节数据经过指定编码转换成字符
- 可对读取到的字符数据经过指定编码转换成字节
转换流的特点:
- 当字节和字符之间有转换动作时;
- 流操作的数据需要编码或解码时。
何时使用转换流?
- InputStreamReader:字节到字符的桥梁
- OutputStreamWriter:字符到字节的桥梁
具体的对象体现:
这两个流对象是字符体系中的成员,它们有转换作用,本身又是字符流,所以在构造的时候需要传入字节流对象进来。
实例:
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));//输出字节转字符流(可逆)
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));//输入字节转字符流(可逆)
总结:
所有的JavaIO对象都自带异常,必须捕捉或抛出;
JavaIO流对象使用结束后必须关流,释放内存空间,否则将有可能造成内存过度消耗甚至内存泄漏;
JavaIO流对象的使用一般都是组合式的,只有组合使用时才能高效率的完成作业(如:设置缓冲流)。
后面还将继续JavaIO流的学习,并进行文章同步。
欢迎建言献策,指导批评,感谢您的支持。