天天看点

Java IO篇(一)1. IO概述2. IO流常用基类3. 字符流的操作4. 字符流缓冲区的读写操作5. 装饰设计模式6 字节流7. 转换流8. 标准输入,输出9. 流操作小结

Java IO篇

  • 1. IO概述
  • 2. IO流常用基类
    • 2.1 字节流的抽象基类:
    • 2.2 字符流的抽象基类
    • 2.3 由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。
  • 3. 字符流的操作
    • 3.1 读取文件
    • 3.2 写出文件
    • 3.3 注意事项
  • 4. 字符流缓冲区的读写操作
    • 4.1 自定义缓冲区读写
    • 4.2 内置缓冲区的BufferedReader和BufferedWriter
  • 5. 装饰设计模式
    • 5.1 什么情况下使用装饰设计模式
    • 5.2 装饰模式的基本格式。
    • 5.3 了解BufferedReader、BufferedWriter的原理。
  • 6 字节流
    • 6.1 自定义缓冲区读写
    • 6.2 BufferedInputStream、BufferedOutputStream
    • 6.3 FileOutputStream
    • 6.4 FileInputStream
  • 7. 转换流
    • InputStreamReader
    • OutputStreamWriter
  • 8. 标准输入,输出
  • 9. 流操作小结

1. IO概述

  • IO流用来处理设备之间的数据传输
  • Java对数据的操作是通过流的方式
  • Java用于操作流的对象都在IO包中
  • 流按操作对象分为两种:字节流与字符流,字节流可以操作任何数据,字符流只能操作纯字符数据比较方便。
  • 流按流向分为:输入流,输出流。

2. IO流常用基类

2.1 字节流的抽象基类:

InputStream

,

OutputStream

2.2 字符流的抽象基类

Reader

,

Writer

2.3 由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。

  • 如:InputStream的子类FileInputStream。
  • 如:Reader的子类FileReader。
  • InputStreamReader是Reader的子类

3. 字符流的操作

3.1 读取文件

//定义字符流关联指定文件
 FileReader reader = new FileReader("Test.txt");
 //读取一个字符,返回int,该字符的码表值
 int ch = reader.read();
 //关闭流,释放资源 
 reader.close(); 
           

3.2 写出文件

//定义字符输出流关联指定文件
FileWriter writer = new FileWriter("Test.txt");
//写出一个字符,接收int码表值
writer.write(97);
//关闭流,释放资源
writer.close();
           

3.3 注意事项

  • 文件路径
    • 定义文件路径时Windows中的目录符号为“\”,但这个符号在Java中是特殊字符,需要转义。可以用“\”或“/”表示。
  • 读取文件
    • 读取文件时必须保证文件存在,否则将抛出FileNotFoundException。
  • 写出文件
    • 写出时文件如不存在时程序会创建新文件,如文件已存在则会清空原文件内容重新写入。
    • 如需追加内容可调用FileWriter构造函数FileWriter(String fileName, boolean append)

4. 字符流缓冲区的读写操作

4.1 自定义缓冲区读写

  • 为什么定义缓冲区
    • 由于单个字符读写需要频繁操作文件,所以效率非常低。我们可以定义缓冲区将要读取或写出的数据缓存,减少操作文件次数。
  • 缓冲区读取
    • 先定义一个数组,然后调用

      FileReader

      读取一个数组的方法。int

      read(char[] cbuf)

  • 缓冲区写出
    • 将要写出的数据存放在数组中,调用FileWriter方法,一次写出一个数组。

      void write(char[] cbuf, int off, int len)

4.2 内置缓冲区的BufferedReader和BufferedWriter

  • Java提供了带缓冲功能的Reader和Writer类:

    BufferedReader,BufferedWriter

  • 这两个类都是提供包装功能,需要提供其他流来使用,给其他流增加缓冲功能
  • 当我们调用

    BufferedReader

    读取数据时,程序会从文件中一次读取8192个字符用来缓冲
  • 当我们调用

    BufferedWriter

    写出数据时,程序会先将数据写出到缓冲数组,直到写满

    8192

    个才一次性刷出到文件
  • 特有方法

    newLine(), readLine()

    注意:

    BufferedReader

    读取时 不会读取换行符,所以写入时会出现乱序,在写入后加

    newLine()

    ;可以解决

Eg1.

需求:在硬盘上,创建一个文件并写入一些文字数据。找到一个专门用于操作文件的Writer子类对象。FileWriter。 后缀名是父类名。 前缀名是该流对象的功能。

import java.io.*;
class  FileWriterDemo
{
	public static void main(String[] args) throws IOException
	{
		//创建一个FileWriter对象。该对象一被初始化就必须要明确被操作的文件。
		//而且该文件会被创建到指定目录下。如果该目录下已有同名文件,将被覆盖。
		//其实该步就是在明确数据要存放的目的地。
		FileWriter fw = new FileWriter("demo.txt");

		//调用write方法,将字符串写入到流中。
		fw.write("abcde");

		//刷新流对象中的缓冲中的数据。
		//将数据刷到目的地中。
		//fw.flush();


		//关闭流资源,但是关闭之前会刷新一次内部的缓冲中的数据。
		//将数据刷到目的地中。
		//和flush区别:flush刷新后,流可以继续使用,close刷新后,会将流关闭。
		fw.close();
	}
}
           

Eg2.

/*
演示对已有文件的数据续写。
*/
import java.io.*;
class  FileWriterDemo3
{
	public static void main(String[] args) throws IOException
	{

		//传递一个true参数,代表不覆盖已有的文件。并在已有文件的末尾处进行数据续写。
		FileWriter fw = new FileWriter("demo.txt",true);

		fw.write("nihao\r\nxiexie");

		fw.close();
	}
}
           

Eg.3

//将C盘一个文本文件复制到D盘。

/*
复制的原理:
其实就是将C盘下的文件数据存储到D盘的一个文件中。

步骤:
1,在D盘创建一个文件。用于存储C盘文件中的数据。
2,定义读取流和C盘文件关联。
3,通过不断的读写完成数据存储。
4,关闭资源。
*/

import java.io.*;

class CopyText 
{
	public static void main(String[] args) throws IOException
	{
		copy_2();
	}


	public static void copy_2()
	{
		FileWriter fw = null;
		FileReader fr = null;
		try
		{
			fw = new FileWriter("SystemDemo_copy.txt");
			fr = new FileReader("SystemDemo.java");

			char[] buf = new char[1024];

			int len = 0;
			while((len=fr.read(buf))!=-1)
			{
				fw.write(buf,0,len);
			}
		}
		catch (IOException e)
		{
			throw new RuntimeException("读写失败");

		}
		finally
		{
			if(fr!=null)
				try
				{
					fr.close();
				}
				catch (IOException e)
				{
				}
			if(fw!=null)
				try
				{
					fw.close();
				}
				catch (IOException e)
				{
				}
		}
	}
	//从C盘读一个字符,就往D盘写一个字符。
	public static void copy_1()throws IOException
	{
		//创建目的地。
		FileWriter fw = new FileWriter("RuntimeDemo_copy.txt");

		//与已有文件关联。
		FileReader fr = new FileReader("RuntimeDemo.java");

		int ch = 0;

		while((ch=fr.read())!=-1)
		{
			fw.write(ch);
		}
		
		fw.close();
		fr.close();

	}
}
           

5. 装饰设计模式

5.1 什么情况下使用装饰设计模式

当我们需要对一个类的功能进行改进、增强的时候

5.2 装饰模式的基本格式。

  • 含有被装饰类的引用
  • 通过构造函数传入被装饰类对象
  • 和被装饰类含有同样的方法,其中调用被装饰类的方法,对其进行改进、增强
  • 和被装饰类继承同一个类或实现同一个接口,可以当做被装饰类来使用

5.3 了解BufferedReader、BufferedWriter的原理。

BufferedReader

BufferedWriter

都是装饰类,他们可以装饰一个

Reader

Writer

,给被装饰的Reader和Writer提供缓冲的功能。就像我们用

BufferedReader

BufferedWriter

装饰

FileReader

FileWriter

,使用的读写功能还是

FileReader

FileWriter

的,但给这两个类的读写添加了缓冲功能。

6 字节流

基本操作与字符流相同,字节流可以操作任意类型数据

6.1 自定义缓冲区读写

  • 原理和字符流相同,都是为了提高效率
  • 定义数组缓冲数据,一次读取一个数组,一次写出一个数组,减少操作文件的次数

6.2 BufferedInputStream、BufferedOutputStream

  • BufferedReader

    BufferedWriter

    原理相同,都是包装类
  • BufferedInputStream

    BufferedOutputStream

    包装

    InputStream``和OutputStream

    提供缓冲功能

6.3 FileOutputStream

public class IoDemo03 {
    public static void main(String[] args) {
            FileOutputStream outputStream=null;
        try {
            //创建源
            //选择流
            outputStream = new FileOutputStream("test.txt",true);
             //操作
            String s="i love you hunan";
            byte[] bytes=s.getBytes();   //字符==>字节  编码
            outputStream.write(bytes,0,bytes.length);
            FileInputStream inputStream = new FileInputStream("test02.txt");
            byte[] bytes1=new byte[1024];
            int read ;
            while ((read=inputStream.read(bytes1))!=-1) {
                  String  str=new String(bytes1,0,read);                             //字节==>字符     解码
                System.out.print(str );
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (outputStream!=null){
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
        }
    }
}
           

6.4 FileInputStream

public class IoDemo01 {
    public static void main(String[] args) {
        //1.确定源 file 或者 字节数组流
         File file=new File("test.txt");
        //System.out.println(file.getAbsolutePath());
        //2.选择流
        InputStream inputStream=null;
        try {
           inputStream=new FileInputStream(file);
            //3.操作
           int temp=0;
           while((temp=inputStream.read())!=-1){
               System.out.print((char) temp);
           }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
           if(inputStream!=null){
               try {
                   inputStream.close();
               } catch (IOException e) {
                   e.printStackTrace();
               }
           }
        }
        //4.释放资源
    }
}
           
public class IoDemo02 {
    public static void main(String[] args) {
        //1.确定源
         File file =new File("test.txt");
        //2.选择流
        FileInputStream inputStream=null;
        try {
            //3.操作
         inputStream = new FileInputStream(file);
            byte[] bytes = new byte[1024];   //缓冲区
            int temp;
         while((temp=inputStream.read(bytes))!=-1){
             System.out.print(new String(bytes));
         }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
            //4.释放资源
        }finally{
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

           

7. 转换流

字符流与字节流之间的桥梁,方便了字符流与字节流之间的操作,字节流中的数据都是字符时,转成字符流操作更高效

注:转换流的输入流和输出流都可以指定编码表,输出指定的编码,输入必须指定相同编码。

InputStreamReader

,

OutputStreamWriter

InputStreamReader

public static void main(String[] args) {
	BufferedReader bufferedReader = null;
	try {
	    // 1. 读取目标文件中的值
	    String fileName = "D:\\初级机试题\\房源库.txt";
	    bufferedReader = new BufferedReader(
	            new InputStreamReader(new BufferedInputStream(new FileInputStream(fileName)),"GBK"));
		// 包装流读取一行数据
	    String s = bufferedReader.readLine();
	    System.out.println(s);
	
	
	} catch (FileNotFoundException e) {
	    e.printStackTrace();
	} catch (IOException e) {
	    e.printStackTrace();
	}
}
           

OutputStreamWriter

public static void main(String[] args) {
    
	BufferedWriter bufferedWriter = null;
	 try {
	     // 1. 读取目标文件中的值
	     String fileName = "D:\\初级机试题\\房源库.txt";
	    
	     bufferedWriter = new BufferedWriter(
	             new OutputStreamWriter(new BufferedOutputStream(new FileOutputStream("Success.txt")), "UTF-8"));
	             
	     bufferedWriter.write("世界你好  我喜欢你");
	 } catch (FileNotFoundException e) {
	     e.printStackTrace();
	 } catch (IOException e) {
	     e.printStackTrace();
	 }finally {
	     if (bufferedWriter !=null) {
	         try {
	             bufferedWriter.close();
	         } catch (IOException e) {
	             e.printStackTrace();
	         }
	     }
	 }
 }
           

8. 标准输入,输出

System

类中的成员变量:

in

out

  1. 它们各代表了系统标准的输入和输出设备。
  2. 默认输入设备是键盘,输出设备是显示器。
  3. System.in的类型是InputStream.
  4. System.out的类型是PrintStream是OutputStream的子类FilterOutputStream 的子类.

9. 流操作小结

通过三个明确来完成。

1,明确源和目的。

​ 源:输入流。InputStream Reader

​ 目的:输出流。OutputStream Writer。

2,操作的数据是否是纯文本。

​ 是:字符流。

​ 不是:字节流。

3,当体系明确后,在明确要使用哪个具体的对象。

​ 通过设备来进行区分:

​ 源设备:内存,硬盘。键盘

​ 目的设备:内存,硬盘,控制台。

Eg.
1,将一个文本文件中数据存储到另一个文件中。复制文件。
	源:因为是源,所以使用读取流。InputStream Reader 
	是不是操作文本文件。
	是!这时就可以选择Reader
	这样体系就明确了。

	接下来明确要使用该体系中的哪个对象。
	明确设备:硬盘。上一个文件。
	Reader体系中可以操作文件的对象是 FileReader

	是否需要提高效率:是!。加入Reader体系中缓冲区 BufferedReader.


	FileReader fr = new FileReader("a.txt");
	BufferedReader bufr = new BufferedReader(fr);


	目的:OutputStream Writer
	是否是纯文本。
	是!Writer。
	设备:硬盘,一个文件。
	Writer体系中可以操作文件的对象FileWriter。
	是否需要提高效率:是!。加入Writer体系中缓冲区 BufferedWriter
	
	FileWriter fw = new FileWriter("b.txt");
	BufferedWriter bufw = new BufferedWriter(fw);
           
练习:将一个图片文件中数据存储到另一个文件中。复制文件。要按照以上格式自己完成三个明确。


---------------------------------------

2,需求:将键盘录入的数据保存到一个文件中。
	这个需求中有源和目的都存在。
	那么分别分析
	源:InputStream Reader
	是不是纯文本?是!Reader
	
	设备:键盘。对应的对象是System.in.
	不是选择Reader吗?System.in对应的不是字节流吗?
	为了操作键盘的文本数据方便。转成字符流按照字符串操作是最方便的。
	所以既然明确了Reader,那么就将System.in转换成Reader。
	用了Reader体系中转换流,InputStreamReader

	InputStreamReader isr = new InputStreamReader(System.in);

	需要提高效率吗?需要!BufferedReader
	BufferedReader bufr = new BufferedReader(isr);

	目的:OutputStream  Writer
	是否是存文本?是!Writer。
	设备:硬盘。一个文件。使用 FileWriter。
	FileWriter fw = new FileWriter("c.txt");
	需要提高效率吗?需要。
	BufferedWriter bufw = new BufferedWriter(fw);


	**************
	扩展一下,想要把录入的数据按照指定的编码表(utf-8),将数据存到文件中。
	
	目的:OutputStream  Writer
	是否是存文本?是!Writer。
	设备:硬盘。一个文件。使用 FileWriter。
	但是FileWriter是使用的默认编码表。GBK.
	
	但是存储时,需要加入指定编码表utf-8。而指定的编码表只有转换流可以指定。
	所以要使用的对象是OutputStreamWriter。
	而该转换流对象要接收一个字节输出流。而且还可以操作的文件的字节输出流。FileOutputStream

	OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d.txt"),"UTF-8");

	需要高效吗?需要。
	BufferedWriter bufw = new BufferedWriter(osw);

	所以,记住。转换流什么使用。字符和字节之间的桥梁,通常,涉及到字符编码转换时,
	需要用到转换流。