java72o_初探JAVA中I/O流(二)

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 }

1e768af733fe2eadfdf56396250f221d.png

注意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();

}

}

142c6441896f54d75a837ee61b922c29.png

从输出文件的内容我们可以发现是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();

}

}

ff56015fff078b6e8d2aa1130cdec622.png

我们想修改第六个Double值。首先算出偏移量,每个double类型8个字节,所以第六个double起始位置的偏移量为40=5*8,所以应该调用seek(5*8)将文件指针指向该处,在调用write方法来修改该值。

7.读写文件工具类

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

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

99be0aa8ce179ff9f8eae77b44427103.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值