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刷新后不能继续输入。  
      
        }  
    } 

要求:用单个字符和字符数组进行分别读取

  1. class FileReaderDemo {  //FileReader的reade()方法.
  2.     public static void main(String[] args) {  
  3.         characters();  
  4.     }  
  5.   
  6.   
  7. /*****************字符数组进行读取*********************/  
  8.     private static void characters() {  
  9.   
  10.         try {  
  11.   
  12.             FileReader fr = new FileReader("Demo.txt");  
  13.             char []  buf = new char[6];   
  14.             //将Denmo中的文件读取到buf数组中。  
  15.             int num = 0;      
  16.             while((num = fr.read(buf))!=-1) {  
  17.   
  18.                 //String(char[] value , int offest,int count) 分配一个新的String,包含从offest开始的count个字符  
  19.                 sop(new String(buf,0,num));  
  20.             }  
  21.             sop('\n');  
  22.             fr.close();  
  23.         }  
  24.         catch (IOException e) {  
  25.             sop(e.toString());  
  26.         }  
  27.     }  
  28.   
  29.   
  30. /*****************单个字母读取*************************/  
  31.     private static void singleReader() {  
  32.           
  33.         try {  
  34.   
  35.             //创建一个文件读取流对象,和指定名称的文件关联。  
  36.             //要保证文件已经存在,否则会发生异常:FileNotFoundException  
  37.             FileReader fr = new FileReader("Demo.txt");  
  38.   
  39.           
  40.             //如何调用读取流对象的read方法?  
  41.             //read()方法,一次读取一个字符,并且自动往下读。如果到达末尾则返回-1  
  42.             int ch = 0;  
  43.             while ((ch=fr.read())!=-1) {  
  44.                 sop((char)ch);  
  45.             }  
  46.             sop('\n');  
  47.             fr.close();  
  48.   
  49.             /*int ch = fr.read(); 
  50.             sop("ch=" + (char)ch); 
  51.  
  52.             int ch2 = fr.read(); 
  53.             sop("ch2=" + (char)ch2); 
  54.  
  55.             //使用结束注意关闭流 
  56.             fr.close(); */    
  57.              
  58.         }  
  59.         catch (IOException e) {  
  60.             sop(e.toString());  
  61.         }  
  62.       
  63.     }  
  64.   
  65.   
  66. /**********************Println************************/  
  67.     private static void sop(Object obj) {  
  68.         System.out.print(obj);  
  69.     }  
  70. }  

File类中的其他属性与方法就不在这儿一一列举了。


RandomAccessFile类

该对象并不是流体系中的一员,其封装了字节流,同时还封装了一个缓冲区(字符数组),通过内部的指针来操作字符数组中的数据。 该对象特点:

  1. 该对象只能操作文件,所以构造函数接收两种类型的参数:a.字符串文件路径;b.File对象。
  2. 该对象既可以对文件进行读操作,也能进行写操作,在进行对象实例化时可指定操作模式(r,rw)

注意:该对象在实例化时,如果要操作的文件不存在,会自动创建;如果文件存在,写数据未指定位置,会从头开始写,即覆盖原有的内容。 可以用于多线程下载或多个线程同时写数据到文件。


下面切入正题:

JavaIO流对象

一、字节流

字节流的继承图:

1.输入字节流InputStream

IO输入字节流的继承图可见上图,可以看出:

  1. InputStream 是所有的输入字节流的父类,它是一个抽象类(不可以实例化)。
  2. ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三种基本的介质流,它们分别从Byte 数组、StringBuffer、和本地文件中读取数据。PipedInputStream 是从与其它线程共用的管道中读取数据。
  3. ObjectInputStream (对象流)和所有FilterInputStream(过滤流) 的子类都是装饰流(装饰器模式的主角),在后边介绍。
 

2.输出字节流OutputStream

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

3.字节流的输入与输出的对应

  1. 图中蓝色的为主要的对应部分,红色的部分就是不对应部分。紫色的虚线部分代表这些流一般要搭配使用。从上面的图中可以看出Java IO 中的字节流是极其对称的。“存在及合理”我们看看这些字节流中不太对称的几个类吧!
  2. PrintStream 也可以认为是一个辅助工具。主要可以向其他输出流,或者FileInputStream 写入数据,本身内部实现还是带缓冲的。本质上是对其它流的综合运用的一个工具而已。一样可以踢出IO 包!System.out 和System.out 就是PrintStream 的实例!


二、字符流

字符的输入输出对应关系图:


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 的对应关系。

缓冲输出流实例:

  1. import java.io.*;  
  2.   
  3. class BufferedReaderDemo {  
  4.     public static void main(String[] args)  throws IOException {  
  5.   
  6.         //创建一个字符读取流流对象,和文件关联  
  7.         FileReader rw = new FileReader("buf.txt");  
  8.   
  9.         //只要将需要被提高效率的流作为参数传递给缓冲区的构造函数即可  
  10.         BufferedReader brw = new BufferedReader(rw);  
  11.   
  12.           
  13.         for(;;) {  
  14.             String s = brw.readLine();  
  15.             if(s==null) break;  
  16.             System.out.println(s);  
  17.         }  
  18.           
  19.         brw.close();//关闭输入流对象  
  20.   
  21.     }  
  22. }  


2.字符输出流Writer

在上面的继承关系图中可以看出:

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

字符输入流实例:

  1. import java.io.*;  
  2.   
  3.  
  4. class BufferedWriterDemo {  
  5.     public static void main(String[] args)  throws IOException {  
  6.   
  7.         //创建一个字符写入流对象  
  8.         FileWriter fw = new FileWriter("buf.txt");  
  9.   
  10.         //为了提高字符写入效率,加入了缓冲技术。  
  11.         //只要将需要被提高效率的流作为参数传递给缓冲区的构造函数即可  
  12.         BufferedWriter bfw = new BufferedWriter(fw);  
  13.   
  14.         //bfw.write("abc\r\nde");  
  15.         //bfw.newLine();               这行代码等价于bfw.write("\r\n"),相当于一个跨平台的换行符  
  16.         //用到缓冲区就必须要刷新  
  17.         for(int x = 1; x < 5; x++) {  
  18.             bfw.write("abc");  
  19.             bfw.newLine();                  //java提供了一个跨平台的换行符newLine();  
  20.             bfw.flush();  
  21.         }  
  22.   
  23.         bfw.flush();                                                //刷新缓冲区  
  24.         bfw.close();                                                //关闭缓冲区,但是必须要先刷新  
  25.   
  26.         //注意,关闭缓冲区就是在关闭缓冲中的流对象  
  27.         fw.close();                                                 //关闭输入流对象  
  28.   
  29.     }  
  30. }  

三、字符流与字节流转换


转换流的特点:
  1. 其是字符流和字节流之间的桥梁
  2. 可对读取到的字节数据经过指定编码转换成字符
  3. 可对读取到的字符数据经过指定编码转换成字节
转换流的特点:
  1. 当字节和字符之间有转换动作时;
  2. 流操作的数据需要编码或解码时。
何时使用转换流?
  1. InputStreamReader:字节到字符的桥梁
  2. OutputStreamWriter:字符到字节的桥梁
具体的对象体现:

这两个流对象是字符体系中的成员,它们有转换作用,本身又是字符流,所以在构造的时候需要传入字节流对象进来。

实例:

BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));//输出字节转字符流(可逆)
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));//输入字节转字符流(可逆)


总结:

所有的JavaIO对象都自带异常,必须捕捉或抛出;

JavaIO流对象使用结束后必须关流,释放内存空间,否则将有可能造成内存过度消耗甚至内存泄漏;

JavaIO流对象的使用一般都是组合式的,只有组合使用时才能高效率的完成作业(如:设置缓冲流)。

后面还将继续JavaIO流的学习,并进行文章同步。

欢迎建言献策,指导批评,感谢您的支持。

猜你喜欢

转载自blog.csdn.net/hu_belif/article/details/80735473