Java I/O系统----------- I/O流的典型使用方式

        尽管可以通过不同的方式组合I/O流泪,但可能也就只用到其中的几种组合。下面的例子可以作为典型的I/O流用法的基本参考,这些示例中异常处理简化为简单的抛出。

1、缓冲输入文件

        如果想要打开一个文件用于字符输入,可以使用以String或File对象作为文件名的FileInputReader,为了提高速度,对那个文件进行缓冲,可将产生的引用传给一个BufferedReader构造器。当readLine()返回null时,就达到了文件的末尾。
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;


public class BufferedInputFile {

	public static String read(String filename) throws IOException {
		BufferedReader in = new BufferedReader(new FileReader(filename));
		String s;
		StringBuilder sb = new StringBuilder();
		while ((s = in.readLine()) != null) {
			sb.append(s+"\n");
		}
		in.close();
		return sb.toString();
	}
	
	public static void main(String[] args) throws IOException {
		System.out.print(read("BufferedInputFile.java"));
	}
}
        字符串sb用来累积文件的全部内容(包括必须添加的换行符,因为readLine()已将它们删除),最后调用close()关闭文件。

2、从内存输入

import java.io.*;

public class MemoryInput {
	public static void main(String[] args) throws IOException {
		StringReader in = new StringReader(read("MemoryInput.java"));
		int c;
		while ((c = in.read()) != -1)
			System.out.print((char) c);
	}

	public static String read(String filename) throws IOException {
		BufferedReader in = new BufferedReader(new FileReader(filename));
		String s;
		StringBuilder sb = new StringBuilder();
		while ((s = in.readLine()) != null) {
			sb.append(s + "\n");
		}
		in.close();
		return sb.toString();
	}
}
注意read()是以int形式返回一下字节,因此必须类型转换为char才能正确打印。

3、格式化的内存输入

        要读取格式化数据,可以使用DataInputStream,它是一个面向字节的I/O类,因此必须使用InputStream类而不是Reader类。当然,可以用InputStream以字节形式读取任何数据(例如一个文件),不过这里使用的是字符串。
import java.io.*;

public class FormattedMemoryInput {
	public static String read(String filename) throws IOException {
		BufferedReader in = new BufferedReader(new FileReader(filename));
		String s;
		StringBuilder sb = new StringBuilder();
		while ((s = in.readLine()) != null) {
			sb.append(s + "\n");
		}
		in.close();
		return sb.toString();
	}
	public static void main(String[] args) throws IOException{
		try {
			DataInputStream in = new DataInputStream(new ByteArrayInputStream(read("FormattedMemoryInput.java").getBytes()));
			while (true) {
				System.out.print((char)in.readByte());
			}
		} catch (EOFException e) {
		      System.err.println("End of stream");
	    }
	}

}
        如果从DataInputStream用readByte()一次一个字节地读取字符,那么任何字节的值都是合法的结果,因此返回值不能用来检测输入是否结束。相反可以使用available()方法查看还有多少个可供存取的字符。下面的例子演示了怎样一次一个字节地读取文件:
import java.io.*;

public class FormattedMemoryInput {
	public static String read(String filename) throws IOException {
		BufferedReader in = new BufferedReader(new FileReader(filename));
		String s;
		StringBuilder sb = new StringBuilder();
		while ((s = in.readLine()) != null) {
			sb.append(s + "\n");
		}
		in.close();
		return sb.toString();
	}
	public static void main(String[] args) throws IOException{
		try {
			DataInputStream in = new DataInputStream(new ByteArrayInputStream(read("FormattedMemoryInput.java").getBytes()));
			while (in.available() != 0) {
				System.out.print((char)in.readByte());
			}
		} catch (EOFException e) {
		      System.err.println("End of stream");
	    }
	}

}
        注意,available()的工作方式会随着所读取的媒介的类型的不同而有所不同;字面意思就是“在没有阻塞的情况下所能读取的字节数”。对应文件,这意味着整个文件,但是对于不同类型的流,可能就不是这样的,因此要谨慎使用。
        也可以通过异常捕获来检测输入的末尾。但是,使用异常进行流控制,被认为是对异常特性的错误使用。

4、基本的文件输出

        FileWriter对象可以向文件写入数据。首先,创建一个与指定文件连接的FileWriter,实际上通常会用BufferedWriter将其包装起来用以缓冲输出,本例中为了提供格式化机制,它被装饰成PrintWriter。按照这种方式创建的数据文件可作为普通文本文件读取。
import java.io.*;


public class BasicFileOutput {
	public static String read(String filename) throws IOException {
		BufferedReader in = new BufferedReader(new FileReader(filename));
		String s;
		StringBuilder sb = new StringBuilder();
		while ((s = in.readLine()) != null) {
			sb.append(s + "\n");
		}
		in.close();
		return sb.toString();
	}
	static String file = "BasicFileOutput.out";
	public static void main(String[] args) throws IOException {
		BufferedReader in = new BufferedReader(new StringReader(read("BasicFileOutput.java")));
		PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(file)));
		int lineCount = 1;
		String s;
		while ((s = in.readLine()) != null) {
			out.println(lineCount++ + ": "+s);
		}
		out.close();
		System.out.println(read(file));
	}

}
        Java SE5在PrintWriter中添加了一个辅助构造器,使得不必每次希望创建文本文件并向其中写入时,都去执行所有的装饰工作,如下例所示:
import java.io.*;

public class FileOutputShortcut {
	public static String read(String filename) throws IOException {
		BufferedReader in = new BufferedReader(new FileReader(filename));
		String s;
		StringBuilder sb = new StringBuilder();
		while ((s = in.readLine()) != null) {
			sb.append(s + "\n");
		}
		in.close();
		return sb.toString();
	}

	static String file = "FileOutputShortcut.out";

	public static void main(String[] args) throws IOException {
		BufferedReader in = new BufferedReader(new StringReader(read("FileOutputShortcut.java")));
		// Here's the shortcut:
		PrintWriter out = new PrintWriter(file);
		int lineCount = 1;
		String s;
		while ((s = in.readLine()) != null)
			out.println(lineCount++ + ": " + s);
		out.close();
		// Show the stored file:
		System.out.println(BufferedInputFile.read(file));
	}
}

5、存储和恢复数据

        PrintWriter可以对数据进行格式化,以便人们阅读。但是为了输出可供另一个“流”恢复的数据,需要用DataOutputStream写入数据,并用DataInputStream恢复数据。注意DataOutputStream和DataInputStream是面向字节的,因此要使用InputStream和OutputStream。
import java.io.*;

public class StoringAndRecoveringData {

	public static void main(String[] args) throws IOException {
		DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("Data.txt")));
		out.writeDouble(3.1415926);
		out.writeUTF("That was pi");
		out.writeDouble(1.41413);
		out.writeUTF("Square root of 2");
		out.close();
		DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream("Data.txt")));
		System.out.println(in.readDouble());
		System.out.println(in.readUTF());
		System.out.println(in.readDouble());
		System.out.println(in.readUTF());
	}

}

6、读写随机访问文件

        使用RandomAccessFile,类似于组合使用了DataInputStream和DataOutputStream(因为它实现了相同接口)。利用seek()可以在文件中到处移动,并修改文件中的某个值。在使用RandomAccessFile时,必须知道文件排版,这样才能正确地操作它。RandomAccessFile拥有读取基本类型和UTF-8字符串的各种具体方法。下面是示例:
import java.io.*;

public class UsingRandomAccessFile {
	static String file = "rtest.dat";
	static void display() throws IOException{
		RandomAccessFile rf = new RandomAccessFile(file, "r");
		for (int i = 0; i < 7; i++) {
			System.out.println("Value "+ i +": "+rf.readDouble());
		}
		System.out.println(rf.readUTF());
		rf.close();
	}
	public static void main(String[] args) throws IOException {
		RandomAccessFile rf = new RandomAccessFile(file, "rw");
		for (int i = 0; i < 7; i++) {
			rf.writeDouble(i*1.414);
		}
		rf.writeUTF("The end of the file");
		rf.close();
		display();
		rf = new RandomAccessFile(file, "rw");
		rf.seek(5*8);
		rf.writeDouble(47.0001);
		rf.close();
		display();
	}

}
因为double是8字节长,所以为了用seek()查找第5个双精度值,只需用5*8来产生查找位置。

7、文件读写的实用工具

import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;


public class TextFile extends ArrayList<String> {

	/**
	 * Read a file as a single string  
	 * @param fileName
	 * @return
	 * @throws IOException 
	 */
	public static String read(String fileName) throws IOException {
		StringBuilder sb = new StringBuilder();
		BufferedReader in = new BufferedReader(new FileReader(new File(fileName).getAbsoluteFile()));
		try {
			String s;
			while ((s = in.readLine()) != null) {
				sb.append(s);
				sb.append("\n");
			}
		} finally {
			in.close();
		}
		return sb.toString();
	}
	/**
	 * Write a single file 
	 * @param fileName
	 * @param text
	 * @throws IOException
	 */
	public static void write(String fileName,String text) throws IOException {
		PrintWriter out = new PrintWriter(new File(fileName).getAbsoluteFile());
		try{
			out.print(text);
		} finally{
			out.close();
		}
	}
	/**
	 * Read a file ,split by any regular expression
	 * @param fileName
	 * @param splitter
	 * @throws IOException
	 */
	public TextFile(String fileName,String splitter) throws IOException{
		super(Arrays.asList(read(fileName).split(splitter)));
		if (get(0).equals("")) {
			remove(0);
		}
	}
	
	public TextFile(String fileName) throws IOException{
		this(fileName, "\n");
	}
	
	public void write(String fileName) throws IOException {
		PrintWriter out = new PrintWriter(new File(fileName).getAbsoluteFile());
		try{
			for (String item:this) {
				out.println(item);
			}
		} finally{
			out.close();
		}
	}
	
	/**
	 * 
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		String fileName = "TextFile.java";
		String file = read(fileName);
		write("test.txt", file);
		TextFile text = new TextFile("test.txt");
		text.write("test2.txt");
		TreeSet<String> words = new TreeSet<String>(new TextFile(fileName, "\\W+"));
		System.out.println(words.headSet("a"));
		
		//下面代码可以统计文档里各个字母出现的次数
		TextFile text2 = new TextFile(fileName,"\\W+");
		Map<Character, Integer> charsStat = new HashMap<Character, Integer>();
		for (String word:text2) {
			for (int i = 0; i < word.length(); i++) {
				Character ch = word.charAt(i);
				Integer freq = charsStat.get(ch);
				charsStat.put(ch, freq == null ? 1:freq+1);
			}
		}
		List<Character> keys = Arrays.asList(charsStat.keySet().toArray(new Character[0]));
		Collections.sort(keys);
		for (Character key:keys) {
			System.out.println(key +" =>"+charsStat.get(key));
		}
	}

}
读取二进制文件
import java.io.*;

public class BinaryFile {
  public static byte[] read(File bFile) throws IOException{
    BufferedInputStream bf = new BufferedInputStream(
      new FileInputStream(bFile));
    try {
      byte[] data = new byte[bf.available()];
      bf.read(data);
      return data;
    } finally {
      bf.close();
    }
  }
  public static byte[]
  read(String bFile) throws IOException {
    return read(new File(bFile).getAbsoluteFile());
  }
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值