Java IO

    自学习Java IO以来,认为难倒是不难,就是比较繁杂,各种方式操作的IO类多如麻,每次使用,都不得不花费大把时间网上溜达一圈,才能完成手头任务。按说,像这些常用的IO操作,对于Java程序员来说,应该达到信手拈来,拿来就用的熟练程度。但我就是记也不住哇,究其原因,就是对Java IO的整体结构不甚了解。结构含糊,就不容易记忆。为了以后方便,于是有了整理一下Java IO的想法,打算简明易懂的记录Java IO的各种分门别类,争取理清思路,常回来看看,印记于脑海,再用时再也不必花费大量时间。不想从2010年2月3日创建该笔记始,一直拖到今天2011-07-13才算有了眉目,但是还不够完整,需要后期继续补充。

    另, 总结代码形成的工具类请参见 文件操作工具类

一、基本概念

 

1. 概述

 

    使用IO时,首先创建一个数据源IO,然后根据需要,创建装饰类IO。Java IO 相关的类总结如下表:

字节流 字符流
       
输入
输出
输入
输出
数据源IO
1   FileInputStream   FileOutputStream       FileReader   FileWriter
2   ByteArrayInputStream   ByteArrayOutputStream   CharArrayReader   CharArrayWriter
3   StringBufferInputStream
  StringReader   StringWriter
4   SequenceInputStream   SequenceOutputStream

5   PipedInputStream   PipedOutputStream   PipedReader   PipedWriter
6   System.in


装饰类IO
7   DataInputStream  DataOutputStream

8   BufferedInputStream  BufferedOutputStream   BufferedReader   BufferedWriter
9   LineNumberInputStream
  LineNumberReader
10   产生格式化输出PrintStream   产生格式化输出PrintWriter
11 PushbackInputStream  一般用于编译器开发 PushBackReader

    说明:

 

2. Java IO的使用原则

 

    决定使用哪个类以及它的构造进程的一般准则如下(不考虑特殊需要)
        第一,考虑最原始的数据格式是什么:是否为文本?
        第二,是输入还是输出?
        第三,是否需要转换流:InputStreamReader, OutputStreamWriter?
        第四,数据来源(去向)是什么:文件?内存?网络?
        第五,是否要缓冲:bufferedReader (特别注明:一定要注意的是readLine()是否有定义,有什么比read, write更特殊的输入或输出方法)
        第六,是否要格式化输出:print?

 

    (1) 按数据来源(去向)分类

        - 是文件: FileInputStream, FileOutputStream, FileReader, FileWriter
        - 是byte[]:ByteArrayInputStream, ByteArrayOutputStream
        - 是Char[]: CharArrayReader, CharArrayWriter
        - 是String: StringBufferInputStream, StringReader, StringWriter
        - 网络数据流:InputStream, OutputStream, Reader, Writer

 

    (2) 按是否格式化输出分
        - 要格式化输出:PrintStream, PrintWriter

 

    (3) 按是否要缓冲分
        - 要缓冲:BufferedInputStream, BufferedOutputStream, BufferedReader, BufferedWriter

 

    (4) 按数据格式分
        - 二进制格式(只要不能确定是纯文本的): InputStream, OutputStream及其所有带Stream结束的子类
        - 纯文本格式(含纯英文与汉字或其他编码方式);Reader, Writer及其所有带Reader, Writer的子类

 

    (5) 按输入输出分
        - 输入:Reader, InputStream类型的子类
        - 输出:Writer, OutputStream类型的子类

 

    (6) 特殊需要
        - 从Stream到Reader,Writer的转换类:InputStreamReader, OutputStreamWriter
        - 对象输入输出:ObjectInputStream, ObjectOutputStream
        - 进程间通信:PipeInputStream, PipeOutputStream, PipeReader, PipeWriter
        - 合并输入:SequenceInputStream
        - 更特殊的需要:PushbackInputStream, PushbackReader, LineNumberInputStream, LineNumberReader

 

二、 例子代码

 

1.文件操作

 

    (1) 从文件读

 

        - 字节流

        FileInputStream 的read方法 : throws IOException
        int read()读取单个字节
        int read(byte[] b)从输入流中将最多 b.length 个字节的数据读入到 byte 数组中

            b - 存储读取数据的缓冲区。
            返回:读入缓冲区的字节总数,如果到达文件末尾而没有更多的数据,返回 -1

        int read(byte[] b, int off,int len)读取len个字节到字节数组b中的指定位置
            b - 目标缓冲区。
            off - 开始存储字节处的偏移量。
            len - 要读取的最大字节数。

//1. 以字节为单位读取文件内容,一次读一个字节
        FileInputStream in = new FileInputStream(file);
        int temp;
        while ((temp = in.read()) != -1) {//将读取的字节赋值给temp
            System.out.write(temp);
        }
    in.close();

 //2. 以字节为单位读取文件内容,一次读多个字节
        int byteread = 0;
        FileInputStream in = new FileInputStream(fileName);
        byte[] tempbytes = new byte[in.available()];// 一次读多个字节
        // 读入多个字节到字节数组中,byteread为一次读入的字节数
        while ((byteread = in.read(tempbytes)) != -1) {
            // String s=new String(tempbytes,"UTF-8");
            System.out.write(tempbytes, 0, byteread);
    }

         //3. 带缓冲的读文件    BufferedInputStream 只有read方法,没有readLine方法

        BufferedInputStream的read方法 :throws IOException
        int read()读取单个字节
        int read(byte[] b)从输入流中将最多 b.length 个字节的数据读入到 byte 数组中

            b - 存储读取数据的缓冲区。
            返回:读入缓冲区的字节总数,如果到达文件末尾而没有更多的数据,返回 -1

        int read(byte[] b, int off,int len)读取len个字节到字节数组b中的指定位置
            b - 目标缓冲区。
            off - 开始存储字节处的偏移量。
            len - 要读取的最大字节数。

        byte[] data = new byte[10];
        BufferedInputStream bis = new BufferedInputStream(
                    new FileInputStream("C:\\readFile.txt"));
        BufferedOutputStream bos = new BufferedOutputStream(
                    new FileOutputStream("C:\\saveFile.txt"));
        while (bis .read(data) != -1) bos.write(data);
        // 将缓冲区中的资料全部写出
        bos.flush();

 

        - 字符流

        FileReader的read方法:
        int read()读取单个字节
        int read(byte[] b)从输入流中将最多 b.length 个字节的数据读入到 byte 数组中

            b - 存储读取数据的缓冲区。
            返回:读入缓冲区的字节总数,如果到达文件末尾而没有更多的数据,返回 -1

        int read(byte[] b, int off,int len)读取len个字节到字节数组b中的指定位置
            b - 目标缓冲区。
            off - 开始存储字节处的偏移量。
            len - 要读取的最大字节数。

//1.一次读多个字符 read(byte[] b)
        char data[] = new char[10];//建立可容纳10个字符的数组
        FileReader fr = new FileReader("algorithms.xml");
        int num = fr.read(data);// 将数据读入字符列表data内
        String str = new String(data, 0, num);// 将字符列表转换成字符串
    fr.close();

//2.一次读多个字符  read(byte[] b, int off,int len)
File fileName=new File("d:\\temp\\save.txt");
        char data[] = new char[(int)fileName.length()];//根据文件长度建立数组
        FileReader fr = new FileReader(fileName);
        int num = fr.read(data,4,6);//从文件中读6个字符放到data数组中,起始位置为data[4]        //返回值num为从文件中读取字符的长度,即6       
        String str = new String(data, 0, num);// 将字符列表转换成字符串
    fr.close();

        //3. 带缓冲的读文件

        BufferedReader的read方法: 增加了一个readLine() 方法throws IOException
        int    read() 读取单个字符。
        int read(char[] cbuf, int off, int len) 将字符读入数组的某一部分。

            cbuf - 目标缓冲区
            off - 开始存储字符处的偏移量
            len - 要读取的最大字符数

        String readLine() 读取一个文本行。

//以行为单位从一个文件读取数据, BufferedReader 有read方法和readLine方法
BufferedReader in = new BufferedReader( new FileReader("F:\\TestIO.java"));
        String s=null;
        while((s = in.readLine()) != null) {
            s+="\n";
System.out.print(s);
}
in.close();    

 

    (2) 写文件

 

        - 字节流

        FileOutputStream的write方法: throws IOException       

        void write(int b)将指定字节b写入文件
           b - 要写入的字节
        void write(byte[] b)将b.length 个字节从指定 byte 数组写入此文件输出流中
        void write(byte[] b,int off,int len)将byte数组中从偏移off开始的len个字节写入文件输出流

            b - 数据
            off - 数据中的起始偏移量
            len - 要写入的字节数

//1. 不带缓冲的写文件
        byte b[]=new byte[512];
        int count=System.in.read(b); //从键盘读取一行字符(写一个读一个,最大读取512个,回车读取结束),存储到缓冲区
        boolean a = true;//true表示追加,false表示覆盖
        FileOutputStream fos = new FileOutputStream("C:\\saveFile.txt", a);
fos.write(b);//把缓冲区b的内容写到指定的文件中
        fos.close();

        //2. 带缓冲的写文件 见文件操作(读)

        BufferedOutputStream的方法: throws IOException
        void write(int b)将指定字节b写入文件
            b - 要写入的字节
        void write(byte[] b)将b.length 个字节从指定 byte 数组写入此文件输出流中
        void write(byte[] b,int off,int len)将byte数组中从偏移off开始的len个字节写入文件输出流
            b - 数据
            off - 数据中的起始偏移量
            len - 要写入的字节数

        void flush()刷新此缓冲的输出流,迫使所有缓冲的输出字节被写出到底层输出流中

 

     - 字符流

        //1. 不带缓冲的写文件
        FileWriter的write方法: throws IOException
        void write(int b)将指定字节b写入文件
            b - 要写入的字节
        void write(byte[] b)将b.length 个字节从指定 byte 数组写入此文件输出流中
        void write(byte[] b,int off,int len)将byte数组中从偏移off开始的len个字节写入文件输出流

            b - 数据
            off - 数据中的起始偏移量
            len - 要写入的字节数

        FileReader fr = null;
        FileWriter fw = null;
        int bi;
        fr = new FileReader("d:\\temp\\read.txt");
        fw = new FileWriter("d:\\temp\\save1.txt");
        while ((bi = fr.read()) != -1) {
            fw.write(bi);//一次读一个字符(一个汉字字符占两个字节,一个英文字符占一个字节)
        }
        fr.close();
        fw.close();

 

        //2. 带缓冲的写文件
        BufferedWriter的方法: throws IOException
        void write(char[] cbuf, int off, int len) 写入字符数组的某一部分。
        void write(int c) 写入单个字符。
        void write(String s, int off, int len) 写入字符串的某一部分

            s - 要写入的字符串
            off - 开始读取字符处的偏移量
            len - 要写入的字符数

        void newLine() 写入一个行分隔符。行分隔符字符串由系统属性 line.separator 定义,并且不一定是单个新行 ('\n') 符
        void flush()刷新此缓冲的输出流,迫使所有缓冲的输出字节被写出到底层输出流中

public class BufferedReaderWriterDemo {
        public static void main(String[] args) {
            try {
            // 缓冲System.in输入流
            // System.in是位流,可以通过InputStreamReader将其转换为字符流
            BufferedReader bufReader = new BufferedReader(
                    new InputStreamReader(System.in));
            // 缓冲FileWriter
            BufferedWriter bufWriter = new BufferedWriter(new FileWriter(
                    "F:\\saveFile.txt"));
            String input = null;
            // 每读一行进行一次写入动作
            while (!(input = bufReader.readLine()).equals("quit")) {
                bufWriter.write(input);
    // newLine()方法写入与操作系统相依的换行字符,依执行环境当时的OS来决定该输出那种换行字符
                bufWriter.newLine();
            }
            bufReader.close();
            bufWriter.close();
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("没有指定文件");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
 

2. 内存读写

 

        ByteArrayInputStream和ByteArrayOutputStream是将位数组当作流输入来源、输出目的地的类。
        CharArrayReader和CharArrayWriter将字符数组当作字符数据输入输出的来源和目的

 

        ByteArrayInputStream的方法: throws IOException
        构造函数:ByteArrayInputStream(byte[] buf)
            创建一个 ByteArrayInputStream,使用 buf 作为其缓冲区数组。
        ByteArrayInputStream(byte[] buf, int offset, int length)
            创建 ByteArrayInputStream,使用 buf 作为其缓冲区数组。
       
     buf - 输入缓冲区。
       
     offset - 缓冲区中要读取的第一个字节的偏移量。
       
     length - 从缓冲区中读取的最大字节数。
        int read()读取单个字节
       
int read(byte[] b)从输入流中将最多 b.length 个字节的数据读入到 byte 数组中
            b - 存储读取数据的缓冲区。
       
     返回:读入缓冲区的字节总数,如果到达文件末尾而没有更多的数据,返回 -1
        int read(byte[] b, int off,int len)读取len个字节到字节数组b中的指定位置
            b - 目标缓冲区。
       
     off - 开始存储字节处的偏移量。
       
     len - 要读取的最大字节数。

        ByteArrayOutputStream的方法:
        byte[]  toByteArray()
            创建一个新的 byte 数组,大小是此输出流的当前大小,并且缓冲区的有效内容已复制到该数组中。
        String toString() 使用平台默认的字符集,通过解码字节将缓冲区内容转换为字符串。
       
String toString(String charsetName)
            使用指定的 charsetName,通过解码字节将缓冲区内容转换为字符串。
        void write(byte[] b, int off, int len)
            将byte数组中从偏移量off开始的len个字节写入此byte数组输出流。
       
     b - 数据。
       
     off - 数据的初始偏移量。
       
     len - 要写入的字节数。
        void write(int b) 将指定的字节写入此 byte 数组输出流。
       
void writeTo(OutputStream out) 将此 byte 数组输出流的全部内容写入到指定的输出流参数中。

public class ByteArrayStreamDemo {
	public static void main(String[] args) {
		try {
			BufferedInputStream bufInputStream = new BufferedInputStream(
					new FileInputStream("F:\\read.txt"));
			ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
			byte[] bytes = new byte[1];
			// 将文件内容写入位数组流
			while (bufInputStream.read(bytes) != -1) {
				arrayOutputStream.write(bytes);
			}
			arrayOutputStream.close();
			bufInputStream.close();
			// toByteArray()方法,以字符方式显示位数组内容
			bytes = arrayOutputStream.toByteArray();
			for (int i = 0; i < bytes.length; i++) {
				System.out.print((char) bytes[i]);
			}
			//toString()方法
			System.out.println(arrayOutputStream.toString());

			// writeTo方法
			//写到控制台输出流(能直接输出)
			arrayOutputStream.writeTo(System.out); 
			FileOutputStream fo=new FileOutputStream("F:\\saveFile.txt",true);
			//写到文件输出流,能直接输出
			arrayOutputStream.writeTo(fo);
			
			// 让使用者输入位置与字符修改位数组内容
			Scanner scanner = new Scanner(System.in);
			System.out.print("请输入修改位置:");
			int pos = scanner.nextInt();
			System.out.println("输入修改字符");
			// 修改数组中对应的字符
			bytes[pos - 1] = (byte) scanner.next().charAt(0);
			// 将位数组内容存回文件
			ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
					bytes); // 参数是数组
			BufferedOutputStream bufOutputStream = new BufferedOutputStream(
					new FileOutputStream("F:\\read.txt"));
			byte[] tmp = new byte[1];
			while (byteArrayInputStream.read(tmp) != -1)//从字节数组中读取数据
				bufOutputStream.write(tmp);
			byteArrayInputStream.close();
			bufOutputStream.flush();
			bufOutputStream.close();
		} catch (ArrayIndexOutOfBoundsException e) {
			System.out.println("请指定文件名称");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
 

        CharArrayReader的方法:
        构造函数:CharArrayReader(char[] buf)创建一个 CharArrayReader,使用 buf 作为其缓冲区数组。
        CharArrayReader (char[] buf, int offset, int length)
             创建 CharArrayReader,使用 buf 作为其缓冲区数组。
             buf - 输入缓冲区。
             offset - 缓冲区中要读取的第一个char的偏移量。
             length - 从缓冲区中读取的最字符数。

        int read()读取单个字符
        int read(char[] c)将最多 c.length 个字符读入到 char 数组中
             c - 存储读取数据的缓冲区。
             返回:读取的实际字符数;如果到达流末尾,则返回 -1
        int read(char[] c, int off,int len)读取len个字节到字节数组b中的指定位置
             c - 目标缓冲区。
             off - 开始存储字符的偏移量。
              len - 要读取的最大字符数。


        CharArrayWriter的方法:
        char[]  toCharArray() 返回输入数据的副本。
        String toString() 将输入的数据转换为字符串。
        void write(char[] b, int off, int len)
             将char数组中从偏移量off开始的len个字节写入此CharArrayWriter数组输出。
             c - 数据。
             off - 数据的初始偏移量。
             len - 要写入的字符数。
        void write(String str, int off, int len) 将字符串的某一部分写入缓冲区。
             str -要写入的字符串。
             off - 数据的初始偏移量。
             len - 要写入的字符数。
        void write(int b) 将一个字符写入缓冲区。
        void writeTo(Writer out) 将缓冲区的内容写入另一个字符流。

public class CharArrayReaderWriterDemo {
	public static void main(String[] args) {
		try {
			BufferedReader bufInputReader = new BufferedReader(new FileReader(
					"F:\\read.txt"));
			CharArrayWriter charArrayWriter = new CharArrayWriter();
			char[] array = new char[1];
			// 将文件读入字符数组
			while (bufInputReader.read(array) != -1) {
				charArrayWriter.write(array);
			}
			charArrayWriter.close();
			bufInputReader.close();

			// toCharArray()方法 显示字符内容
			array = charArrayWriter.toCharArray();
			for (int i = 0; i < array.length; i++) {
				System.out.print(array[i] + " ");
			}
			//toString()方法
			System.out.println(charArrayWriter.toString());
			
			// writeTo方法  写到文件输出流,能直接输出
			FileWriter fw=new FileWriter("F:\\saveFile.txt");
			charArrayWriter.writeTo(fw);
			fw.close();
			
			// 将字符数组内容存回文件
			CharArrayReader charArrayReader = new CharArrayReader(array);
			BufferedWriter bufWriter = new BufferedWriter(new FileWriter("F:\\read.txt"));
			char[] tmp = new char[1];
			while (charArrayReader.read(tmp) != -1) {
				bufWriter.write(tmp);
			}
			charArrayReader.close();
			bufWriter.flush();
			bufWriter.close();
		} catch (ArrayIndexOutOfBoundsException e) {
			System.out.println("请指定文件名!");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
 

3. 其它

 

        InputStreamReader 和 OutputStreamWriter,用于字节流与字符流之间的转换
        InputStreamReader从一个数据源读取字节,并自动将其转换成Unicode字符,除非特别声明
        OutputStreamWriter将字符的Unicode编码写到输出流,如果你的使用的不是Unicode字符,OutputStreamWriter会将你的字符编码转换成Unicode编码。
        在InputStreamReader和OutputStreamWriter的结尾链接一个BufferedReader和BufferedWriter是一个好主意。记住对BufferedWriter使用flush()方法。

 

        // 读写文件的编码:
        InputStreamReader r = new InputStreamReader(new FileInputStream(fileName), "utf-8");
        OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(fileName),"utf-8");

你可能感兴趣的:(java)