1.缓冲输入文件
FileReader
BufferedReader
FileReader可以直接对文件进行读操作。但是简化编程,加快读取速度,我们加入了缓冲机制,使用了BufferedReader。BufferedReader内置了一个char[]数组(大小为8192)作为缓冲区,每次调用fill()函数将该缓冲区尽可能填满。而我们自己的程序在调用BufferedReader提供的方法时,实质上是从该缓冲区读取的。
BufferedReader中的fill()方法
1 private void fill() throwsIOException {2 intdst;3 if (markedChar <=UNMARKED) {4 /*No mark*/
5 dst = 0;6 } else{7 /*Marked*/
8 int delta = nextChar -markedChar;9 if (delta >=readAheadLimit) {10 /*Gone past read-ahead limit: Invalidate mark*/
11 markedChar =INVALIDATED;12 readAheadLimit = 0;13 dst = 0;14 } else{15 if (readAheadLimit <=cb.length) {16 /*Shuffle in the current buffer*/
17 System.arraycopy(cb, markedChar, cb, 0, delta);18 markedChar = 0;19 dst =delta;20 } else{21 /*Reallocate buffer to accommodate read-ahead limit*/
22 char ncb[] = new char[readAheadLimit];23 System.arraycopy(cb, markedChar, ncb, 0, delta);24 cb =ncb;25 markedChar = 0;26 dst =delta;27 }28 nextChar = nChars =delta;29 }30 }31
32 intn;33 do{34 n = in.read(cb, dst, cb.length -dst);//该方法调用了read方法35 } while (n == 0);36 if (n > 0) {37 nChars = dst +n;38 nextChar =dst;39 }40 }
BufferedReader中的read()方法
1 public int read() throwsIOException {2 synchronized(lock) {3 ensureOpen();4 for(;;) {5 if (nextChar >=nChars) {6 fill(); //调用内置的fill()方法7 if (nextChar >=nChars)8 return -1;9 }10 if(skipLF) {11 skipLF = false;12 if (cb[nextChar] == '\n') {13 nextChar++;14 continue;15 }16 }17 return cb[nextChar++]; //返回给用户的是个缓冲区18 }19 }20 }
从上面的代码中可以看出BufferedReader对我们普通的Reader进行了包装,通过缓冲区机制提高了用户读写的速度。
使用方式:
1 packagecom.dy.xidian;2
3 importjava.io.BufferedReader;4 importjava.io.FileReader;5
6 public classBufferedInputFile {7 public static String read(String filename) throwsException {8 BufferedReader in = new BufferedReader(newFileReader(filename));9 String s;10 StringBuilder sb = newStringBuilder();11 while ((s = in.readLine()) != null) {12 sb.append(s);13 }14 in.close();15 returnsb.toString();16 }17
18 public static void main(String[] args) throwsException {19 if (args.length != 1) {20 System.out.println("Usage: BufferedInputFile filepath!");21 }22 String s = read(args[0]);23 System.out.println(s);24 }25 }
注意readline()的使用:
读入的数据要注意有/r或/n或/r/n
没有数据时会阻塞,在数据流异常或断开时才会返回null
使用socket之类的数据流时,要避免使用readLine(),以免为了等待一个换行/回车符而一直阻塞
2.从内存输入
StringReader的输入是一个String对象,所以StringReader是从内存读取数据的。上一个例子输出的是个String对象,我们恰好可以利用一下。
1 public classMemoryInput {2 public static void main(String[] args) throwsException {3 String filename = "E:/html/111.php";4 StringReader sr = newStringReader(BufferedInputFile.read(filename));5 intc;6 while ((c = sr.read()) != -1)7 System.out.print((char) c);8 }9 }
3.格式化的内存输入
要读取格式化数据,可以使用DataInputStream,它是一个面向字节的I/O类。
packagecom.dy.xidian;importjava.io.BufferedReader;importjava.io.ByteArrayInputStream;importjava.io.DataInputStream;importjava.io.FileNotFoundException;importjava.io.FileReader;importjava.io.IOException;classBufferedInputFile {
BufferedReader br;public BufferedInputFile(String path) throwsFileNotFoundException {
br= new BufferedReader(newFileReader(path));
}public String read() throwsIOException {
StringBuilder sb= newStringBuilder();
String s;while ((s = br.readLine()) != null)
sb.append(s);returnsb.toString();
}
}public classFormattedMemoryInput {public static void main(String[] args) throwsIOException {
String path= "E:/html/utf-8.php";
DataInputStream in= new DataInputStream(newByteArrayInputStream(
path.getBytes()));while (in.available() != 0)
System.out.print((char) in.readByte());
}
}
4.基本的文件输出
FileWriter对象可以向文件中写入数据。首先创建一个与指定文件连接的FileWriter。然后我们对其进行装饰。为了提高写的效率,加入缓冲机制,使用BufferedWriter类对其进行包装。为了能够格式化输出,使用PrintWriter类包装。
packagecom.dy.xidian;importjava.io.BufferedWriter;importjava.io.FileWriter;importjava.io.IOException;importjava.io.PrintWriter;public classBasicFileOutput {static String File = "E:/html/utf-8.php";public static void main(String[] args) throwsIOException {
PrintWriter os= new PrintWriter(newBufferedWriter(newFileWriter(File)));
String s1= "hello world!";
String s2= "世界 你好";
os.println(s1);
os.print(s2);
os.close();
}
}
更为简单的方式:利用PrintWriter提供的辅助构造器
1 public PrintWriter(String fileName) throwsFileNotFoundException {2 this(new BufferedWriter(new OutputStreamWriter(newFileOutputStream(fileName))),3 false);4 }5
6 /*Private constructor*/
7 privatePrintWriter(Charset charset, File file)8 throwsFileNotFoundException9 {10 this(new BufferedWriter(new OutputStreamWriter(newFileOutputStream(file), charset)),11 false);12 }
packagecom.dy.xidian;importjava.io.IOException;importjava.io.PrintWriter;public classBasicFileOutput {static String File = "E:/html/utf-8.php";public static void main(String[] args) throwsIOException {
PrintWriter os= newPrintWriter(File);
String s1= "hello world!";
String s2= "世界 你好";
os.println(s1);
os.print(s2);
os.close();
}
}
5.储存和恢复数据
DataInputStream和DataOutputStream一般用来对对象的成员属性读取和输出操作。这两个类都是面向字节流的。
packagecom.dy.xidian;importjava.io.BufferedInputStream;importjava.io.BufferedOutputStream;importjava.io.DataInputStream;importjava.io.DataOutputStream;importjava.io.FileInputStream;importjava.io.FileOutputStream;importjava.io.IOException;public classStoringAndRecoveringData {public static void main(String args[]) throwsIOException {
String path= "E:/html/utf-8.php";
FileOutputStream fs= newFileOutputStream(path);
DataOutputStream os= new DataOutputStream(newBufferedOutputStream(fs));
os.writeDouble(3141.5);
os.writeUTF("这是Pi1"); //使用UTF-8编码
os.close();
DataInputStream is= new DataInputStream(newBufferedInputStream(newFileInputStream(path)));
System.out.println(is.readDouble()); //先读double
System.out.println(is.readUTF()); //在读字符串
is.close();
}
}
从输出文件的内容我们可以发现是DataOutputStream输出的是一大堆编码,这些编码只适合DataInputStream来读取。这种方式可以用来进行对象的序列化存储。并且读取的顺序要与存储的顺序保持一致。
6.随机访问文件
RandomAccessFile提供了随机访问的文件的方法,它可以看成是DataInputStream和DataOutputStream的组合。RandomAccessFile也是面向字节流的,所以我们想修改文件某处的值时,需要计算出该值的偏移量(单位为字节),通过seek方法,将文件指针指向该处,才可以修改成功。
packagecom.dy.xidian;importjava.io.IOException;importjava.io.RandomAccessFile;public classUsingRandomAccessFile {static String file = "E:/html/utf-8.php";static void display() throwsIOException {
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) throwsIOException {
RandomAccessFile rf= new RandomAccessFile(file, "rw");for (int i = 0; i < 7; i++)
rf.writeDouble(i* 1.414);
rf.writeUTF("文件末尾");
rf.close();
display();
rf= new RandomAccessFile(file, "rw");
rf.seek(5 * 8);
rf.writeDouble(47.0001);
rf.close();
display();
}
}
我们想修改第六个Double值。首先算出偏移量,每个double类型8个字节,所以第六个double起始位置的偏移量为40=5*8,所以应该调用seek(5*8)将文件指针指向该处,在调用write方法来修改该值。
7.读写文件工具类
1 packagecom.dy.xidian;2
3 importjava.io.BufferedReader;4 importjava.io.File;5 importjava.io.FileInputStream;6 importjava.io.IOException;7 importjava.io.InputStreamReader;8 importjava.io.PrintWriter;9 importjava.util.ArrayList;10 importjava.util.Arrays;11 importjava.util.TreeSet;12
13 public class TextFile extends ArrayList{14
15 /**
16 *17 */
18 private static final long serialVersionUID = 1L;19
20 /**
21 *22 *@param文件名23 *@param字符集编码24 *@return文件内容25 */
26 public staticString read(String fileName, String Charset) {27 StringBuilder sb = newStringBuilder();28 try{29 BufferedReader br = new BufferedReader(newInputStreamReader(30 newFileInputStream(fileName), Charset));31 try{32 String s;33 while ((s = br.readLine()) != null) {34 sb.append(s);35 sb.append("\n");36 }37 } finally{38 br.close();39 }40 } catch(IOException e) {41 throw newRuntimeException(e);42 }43 returnsb.toString();44 }45
46 /**
47 *48 *@param文件名49 *@param文本内容50 */
51 public static voidwrite(String fileName, String text) {52 try{53 PrintWriter out = newPrintWriter(54 newFile(fileName).getAbsoluteFile());55 try{56 out.print(text);57 } finally{58 out.close();59 }60 } catch(IOException e) {61 throw newRuntimeException();62 }63 }64
65 publicTextFile(String fileName, String splitter) {66 super(Arrays.asList(read(fileName, "utf-8").split(splitter)));67 //split()会留一个空字符串在开始的位置
68 if (get(0).equals(""))69 remove(0);70 }71
72 publicTextFile(String fileName) {73 this(fileName, "\n");74 }75
76 public voidwrite(String fileName) {77 try{78 PrintWriter out = newPrintWriter(79 newFile(fileName).getAbsoluteFile());80 try{81 for (String item : this) {82 out.print(item);83 }84 } finally{85 out.close();86 }87 } catch(IOException e) {88 throw newRuntimeException();89 }90 }91
92 public static voidmain(String[] args) {93 String file = TextFile.read("com/dy/xidian/TextFile.java", "utf-8");94 TextFile.write("test.txt", file);95 TextFile text = new TextFile("test.txt");96 text.write("test2.txt");97 TreeSet words = new TreeSet(newTextFile(98 "com/dy/xidian/TextFile.java", "\\W+"));99 for(String string : words) {100 System.out.println(string);101 }102 System.out.println(words.headSet("a"));103 }104 }
View Code