1.缓冲输入文件


  • FileReader

  • BufferedReader

  FileReader可以直接对文件进行读操作。但是简化编程,加快读取速度,我们加入了缓冲机制,使用了BufferedReader。BufferedReader内置了一个char[]数组(大小为8192)作为缓冲区,每次调用fill()函数将该缓冲区尽可能填满。而我们自己的程序在调用BufferedReader提供的方法时,实质上是从该缓冲区读取的。

  BufferedReader中的fill()方法

  private void fill() throws IOException {
int dst;
if (markedChar <= UNMARKED) {
/* No mark */
dst = 0;
} else {
/* Marked */
int delta = nextChar - markedChar;
if (delta >= readAheadLimit) {
/* Gone past read-ahead limit: Invalidate mark */
markedChar = INVALIDATED;
readAheadLimit = 0;
dst = 0;
} else {
if (readAheadLimit <= cb.length) {
/* Shuffle in the current buffer */
System.arraycopy(cb, markedChar, cb, 0, delta);
markedChar = 0;
dst = delta;
} else {
/* Reallocate buffer to accommodate read-ahead limit */
char ncb[] = new char[readAheadLimit];
System.arraycopy(cb, markedChar, ncb, 0, delta);
cb = ncb;
markedChar = 0;
dst = delta;
}
nextChar = nChars = delta;
}
} int n;
do {
n = in.read(cb, dst, cb.length - dst);//该方法调用了read方法
} while (n == 0);
if (n > 0) {
nChars = dst + n;
nextChar = dst;
}
}

  BufferedReader中的read()方法

 public int read() throws IOException {
synchronized (lock) {
ensureOpen();
for (;;) {
if (nextChar >= nChars) {
fill(); //调用内置的fill()方法
if (nextChar >= nChars)
return -1;
}
if (skipLF) {
skipLF = false;
if (cb[nextChar] == '\n') {
nextChar++;
continue;
}
}
return cb[nextChar++]; //返回给用户的是个缓冲区
}
}
}

从上面的代码中可以看出BufferedReader对我们普通的Reader进行了包装,通过缓冲区机制提高了用户读写的速度。

使用方式:

 package com.dy.xidian;

 import java.io.BufferedReader;
import java.io.FileReader; public class BufferedInputFile {
public static String read(String filename) throws Exception {
BufferedReader in = new BufferedReader(new FileReader(filename));
String s;
StringBuilder sb = new StringBuilder();
while ((s = in.readLine()) != null) {
sb.append(s);
}
in.close();
return sb.toString();
} public static void main(String[] args) throws Exception {
if (args.length != 1) {
System.out.println("Usage: BufferedInputFile filepath!");
}
String s = read(args[0]);
System.out.println(s);
}
}

注意readline()的使用:

  1. 读入的数据要注意有/r或/n或/r/n
  2. 没有数据时会阻塞,在数据流异常或断开时才会返回null
  3. 使用socket之类的数据流时,要避免使用readLine(),以免为了等待一个换行/回车符而一直阻塞

2.从内存输入


  StringReader的输入是一个String对象,所以StringReader是从内存读取数据的。上一个例子输出的是个String对象,我们恰好可以利用一下。

 public class MemoryInput {
public static void main(String[] args) throws Exception {
String filename = "E:/html/111.php";
StringReader sr = new StringReader(BufferedInputFile.read(filename));
int c;
while ((c = sr.read()) != -1)
System.out.print((char) c);
}
}

3.格式化的内存输入


  要读取格式化数据,可以使用DataInputStream,它是一个面向字节的I/O类。

package com.dy.xidian;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException; class BufferedInputFile {
BufferedReader br; public BufferedInputFile(String path) throws FileNotFoundException {
br = new BufferedReader(new FileReader(path));
} public String read() throws IOException {
StringBuilder sb = new StringBuilder();
String s;
while ((s = br.readLine()) != null)
sb.append(s);
return sb.toString();
}
}
public class FormattedMemoryInput {
public static void main(String[] args) throws IOException {
String path = "E:/html/utf-8.php";
DataInputStream in = new DataInputStream(new ByteArrayInputStream(
path.getBytes()));
while (in.available() != 0)
System.out.print((char) in.readByte());
}
}

4.基本的文件输出


  FileWriter对象可以向文件中写入数据。首先创建一个与指定文件连接的FileWriter。然后我们对其进行装饰。为了提高写的效率,加入缓冲机制,使用BufferedWriter类对其进行包装。为了能够格式化输出,使用PrintWriter类包装。

package com.dy.xidian;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter; public class BasicFileOutput {
static String File = "E:/html/utf-8.php";
public static void main(String[] args) throws IOException {
PrintWriter os = new PrintWriter(new BufferedWriter(
new FileWriter(File)));
String s1 = "hello world!";
String s2 = "世界 你好";
os.println(s1);
os.print(s2);
os.close();
}
}

  更为简单的方式:利用PrintWriter提供的辅助构造器

    public PrintWriter(String fileName) throws FileNotFoundException {
this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName))),
false);
} /* Private constructor */
private PrintWriter(Charset charset, File file)
throws FileNotFoundException
{
this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), charset)),
false);
}
package com.dy.xidian;

import java.io.IOException;
import java.io.PrintWriter; public class BasicFileOutput {
static String File = "E:/html/utf-8.php";
public static void main(String[] args) throws IOException {
PrintWriter os = new PrintWriter(File);
String s1 = "hello world!";
String s2 = "世界 你好";
os.println(s1);
os.print(s2);
os.close();
}
}

5.储存和恢复数据


  DataInputStream和DataOutputStream一般用来对对象的成员属性读取和输出操作。这两个类都是面向字节流的。

package com.dy.xidian;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException; public class StoringAndRecoveringData {
public static void main(String args[]) throws IOException {
String path = "E:/html/utf-8.php";
FileOutputStream fs = new FileOutputStream(path);
DataOutputStream os = new DataOutputStream(new BufferedOutputStream(fs));
os.writeDouble(3141.5);
os.writeUTF("这是Pi1"); //使用UTF-8编码
os.close();
DataInputStream is = new DataInputStream(new BufferedInputStream(
new FileInputStream(path)));
System.out.println(is.readDouble()); //先读double
System.out.println(is.readUTF()); //在读字符串
is.close();
}
}

  

  从输出文件的内容我们可以发现是DataOutputStream输出的是一大堆编码,这些编码只适合DataInputStream来读取。这种方式可以用来进行对象的序列化存储。并且读取的顺序要与存储的顺序保持一致。

6.随机访问文件


  RandomAccessFile提供了随机访问的文件的方法,它可以看成是DataInputStream和DataOutputStream的组合。RandomAccessFile也是面向字节流的,所以我们想修改文件某处的值时,需要计算出该值的偏移量(单位为字节),通过seek方法,将文件指针指向该处,才可以修改成功。

package com.dy.xidian;

import java.io.IOException;
import java.io.RandomAccessFile; public class UsingRandomAccessFile {
static String file = "E:/html/utf-8.php";
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("文件末尾");
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.读写文件工具类


 package com.dy.xidian;

 import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.TreeSet; public class TextFile extends ArrayList<String> { /**
*
*/
private static final long serialVersionUID = 1L; /**
*
* @param 文件名
* @param 字符集编码
* @return 文件内容
*/
public static String read(String fileName, String Charset) {
StringBuilder sb = new StringBuilder();
try {
BufferedReader br = new BufferedReader(new InputStreamReader(
new FileInputStream(fileName), Charset));
try {
String s;
while ((s = br.readLine()) != null) {
sb.append(s);
sb.append("\n");
}
} finally {
br.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
return sb.toString();
} /**
*
* @param 文件名
* @param 文本内容
*/
public static void write(String fileName, String text) {
try {
PrintWriter out = new PrintWriter(
new File(fileName).getAbsoluteFile());
try {
out.print(text);
} finally {
out.close();
}
} catch (IOException e) {
throw new RuntimeException();
}
} public TextFile(String fileName, String splitter) {
super(Arrays.asList(read(fileName, "utf-8").split(splitter)));
// split()会留一个空字符串在开始的位置
if (get(0).equals(""))
remove(0);
} public TextFile(String fileName) {
this(fileName, "\n");
} public void write(String fileName) {
try {
PrintWriter out = new PrintWriter(
new File(fileName).getAbsoluteFile());
try {
for (String item : this) {
out.print(item);
}
} finally {
out.close();
}
} catch (IOException e) {
throw new RuntimeException();
}
} public static void main(String[] args) {
String file = TextFile.read("com/dy/xidian/TextFile.java", "utf-8");
TextFile.write("test.txt", file);
TextFile text = new TextFile("test.txt");
text.write("test2.txt");
TreeSet<String> words = new TreeSet<String>(new TextFile(
"com/dy/xidian/TextFile.java", "\\W+"));
for (String string : words) {
System.out.println(string);
}
System.out.println(words.headSet("a"));
}
}

初探JAVA中I/O流(二)的更多相关文章

  1. 初探JAVA中I/O流(一)

    一.流 流,这里是对数据交换的形象称法.进程是运行在内存中的,在运行的过程中避免不了会与外界进行数据交互.比如将数据从硬盘.控制台.管道甚至是套接字(具体点应该是我们电脑上的网卡)读到我们进程锁所占据 ...

  2. Java中的IO流(二)

    上一篇<Java中的IO流(一)>把学习IO流的字符流作了一下记录,本篇把字节流记录一下. 一,Java中的字节流 Java中的字节流的操作方式与字符流的操作方式大致相同,连方法名都是类似 ...

  3. Java中的IO流总结

    Java中的IO流总结 1. 流的继承关系,以及字节流和字符流. 2. 节点流FileOutputStream和FileInputStream和处理流BufferedInputStream和Buffe ...

  4. Java中的IO流(五)

    上一篇<Java中的IO流(四)>记录了一下Properties类,此类不属于IO流,它属于集合框架.接下来说一下IO流中的其它流 一,打印流PrintStream PrintStream ...

  5. Java中的IO流(六)

    上一篇<Java中的IO流(五)>把流中的打印流PrintStream,PrintWriter,序列流SequenceInputStream以及结合之前所记录的知识点完成了文件的切割与文件 ...

  6. Java中的IO流(四)

    上一篇<Java中的IO流(三)>把IO流中的文件及目录操作的对象File类记录了一下,本篇把本不属性IO流但又和IO流有关系的一个对象作一下记录,此对象本属于集合框架里的一个子集,即Pr ...

  7. Java中的IO流(三)

    上一篇<Java中的IO流(二)>把学习Java的字符流以及转换流作了一下记录,从本篇开始将把IO流中对文件或文件夹操作的对象File类的学习进行一下记录. 一,File类的构造函数及字段 ...

  8. java中的Stream流

    java中的Stream流 说到Stream便容易想到I/O Stream,而实际上,谁规定"流"就一定是"IO流"呢?在Java 8中,得益于Lambda所带 ...

  9. java中的IO流

    Java中的IO流 在之前的时候我已经接触过C#中的IO流,也就是说集中数据固化的方式之一,那么我们今天来说一下java中的IO流. 首先,我们学习IO流就是要对文件或目录进行一系列的操作,那么怎样操 ...

随机推荐

  1. 关于HADOOP HA 中DFSZKFC的理解

    [转自uc技术博客:http://tech.uc.cn/?p=252] FC是要和NN一一对应的,两个NN就要部署两个FC.它负责监控NN的状态,并及时的把状态信息写入ZK.它通过一个独立线程周期性的 ...

  2. 动手学习TCP:数据传输

    前面的文章介绍了TCP状态变迁,以及TCP状态变迁图中的一些特殊状态. 本文主要看看TCP数据传输过程中需要了解的一些重要点: MSS(Maximum Segment Size) Seq号和Ack号的 ...

  3. 快速理解Kafka分布式消息队列框架

    作者:刘旭晖 Raymond 转载请注明出处 Email:colorant at 163.com BLOG:http://blog.csdn.net/colorant/ ==是什么 == 简单的说,K ...

  4. 【C++】array初始化0

    让代码...优雅? ==================分割线==================== 局部数组:没有默认值,如果声明的时候不定义,则会出现随机数(undefined):如果声明的长度 ...

  5. java读取word内容

    暂时只写读取word内容的方法. 依赖的jar: poi-3.9-20121203.jarpoi-ooxml-3.9-20121203.jarxmlbeans-2.3.0.jar package co ...

  6. ASP.NET URL伪静态重写实现方法

    ASP.NET URL伪静态重写实现方法 首先说下,ASP.NET URL伪静态只是将~/a_1.html指向到了~/a.aspx?ID=1,但a.aspx还是真实存在的,你不用./a_1.html来 ...

  7. 边工作边刷题:70天一遍leetcode: day 101

    dp/recursion的方式和是不是game无关,和game本身的规则有关:flip game不累加值,只需要一个boolean就可以.coin in a line II是从一个方向上选取,所以1d ...

  8. CSS3属性选择器与(:not)选择器

    一:css3属性选择器: img[alt]{ border:2px dashed #000; } 这个选择器会匹配页面标签中任何一个含有alt属性的图片标签.   还可以通过设定属性值来缩小匹配范围: ...

  9. UVALive 6264 Conservation --拓扑排序

    题意:一个展览有n个步骤,告诉你每一步在那个场馆举行,总共2个场馆,跨越场馆需要1单位时间,先给你一些约束关系,比如步骤a要在b前执行,问最少的转移时间是多少. 解法:根据这些约束关系可以建立有向边, ...

  10. ZOJ 1808 Immediately Decodable

    字典树较简单题,无需维护标记,注意细节即可. 代码: #include <iostream> #include <cstdio> #include <cstring> ...