目录
1. I/O流概述
2.字节流
2.1 字节流概述
2.2字节输出流
2.2.1 字节输出流OutputStream
2.2.2 FileOutputStream类
2.3 字节输入流
2.3.1 字节输入流InputStream
2.3.2 FileInputStream类
2.3.3 字节流练习
1.复制文件
2.拷贝指定路径的文件到指定路径下
3.统计一个文件中字母或数字出现的个数
4.将集合中的数据存入文件中,再读取文件的数据存入集合中
3.I/O流异常处理
3.1 正常情况下的处理方式
3.2 JDK7资源自动关闭
4.字符流
4.1 编码
4.1.1默认编码写入和读取
4.1.2 指定编码写入和读取
4.1.3 字符编码表
4.2 字符输入流
4.2.1 Reader
4.2.2 FileReader类
4.2.3 使用FileReader读取包含中文的文件
4.3 字符输出流
4.3.1 Writer类
4.3.2 FileWriter类
4.3.3flush()和close()的区别?
4.3.4FileWriter写入中文到文件中
4.3.5 字符流练习题
复制文本文件
5.转换流
5.1 OutputStreamWriter
5.2 InputStreamReader
6. 缓冲流
6.1 字节缓冲流
6.1.1 字节缓冲输出流BufferedOutputStream
6.1.2 字节缓冲输入流BufferedInputStream
6.1.3 缓冲流效率的对比
6.2 字符缓冲流
6.2.1 字符缓冲输出流BufferedWriter
6.2.2 字符缓冲输入流BufferedReader
6.2.3 练习
1.使用字符缓冲流优化 数据集合 互转
2.使用字符缓冲流拷贝文件
7.对象序列化流
8.打印流
8.1 PrintStream
8.2 PrintWriter
9.流的使用
10.总结
1. I/O流概述
I/O(Input/Output)流,即输入输出流,是java中实现输入输出的基础,它可以方便的实现数据的输入输出操作。
程序需要实现与设备和不同介质之间的数据传输,例如:键盘录入、读取电脑文件等,Java将这种通过不同输入输出设备(键盘,显示器,网络)等之间的数据传输抽象表述为“流”
- 按照操作的数据不同,可以分为:
- 字节流:字节流可以操作任何数据,因为在计算机中任何数据都是以字节的形式存储的
- 字符流:字符流只能操作纯字符数据,比较方便。
- 按照流向分,又可以分为:
- 输入流:只能从流中读取数据
- 输出流:只能从流中写入数据
注:I/O流在进行数据读写操作时会出现异常,则需抛出或捕获IOException异常
2.字节流
2.1 字节流概述
在计算机中,无论是文本、图片、音频还是视频,所有文件都是以二进制(字节)形式存在的,I/O流中针对字节的输入输出提供了一系列的流,统称为字节流。
2.2字节输出流
2.2.1 字节输出流OutputStream
OutputStream是抽象类,是所有字节输出流类的超类。操作的数据都是字节,该类定义了字节输出流的基本共性功能方法
OutputStream中定义的方法:
方法 方法声明 功能描述 public void write(int b)
向输出流写入一个字节(会根据ASCII码进行转换) public void write(byte b[]) 将b.length个字节从指定byte数组中写入此文件输出流中 public void write(byte b[], int off, int len) 将指定byte数组中从偏移量off开始的len个字节写入此输出流 public void close() 关闭此输出流,并释放与此流相关的所有系统资源
2.2.2 FileOutputStream类
OutputStream有很多子类,其中子类FileOutputStream可用来写入数据到文件。
FileOutputStream类,即文件输出流,是用于将数据写入 File的输出流。
FileOutputStream的构造方法,构造方法可以接受File、String类型的数据,append为是否追加数据(续写文件):
构造方法 方法声明 功能描述 public FileOutputStream(String name) 创建一个具有指向名称的文件中写入数据的输出文件流 public FileOutputStream(String name, boolean append) 创建一个向具有指定name的文件中写入数据的输出文件流(append为true时,可续写文件) public FileOutputStream(File file) 创建一个向指定File对象表示的文件中写入数据的文件输出流
public FileOutputStream(File file, boolean append) 创建一个向指定File对象表示的文件中写入数据的文件输出流append为true时,可续写文件)
基本用法:
import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class Demo1 { public static void main(String[] args) throws Exception { //创建文件输出流对象,并指定输出文件名称 //若文件指定输出文件名称"out.txt"不存在,则需抛出或捕获FileNotFoundException异常,自动会创建异常 FileOutputStream fos = new FileOutputStream("out.txt"); //第二种创建方式(也可使用匿名方式) //File file = new File("out.txt"); //FileOutputStream fos = new FileOutputStream(file); //I/O流在进行数据读写操作时会出现异常,则需抛出或捕获IOException异常 fos.write(97);//ascii码 对应a //写入数组数据 byte[] bytes = {98,99,100}; //对应bcd fos.write(bytes); //写入hello String s = "\nhello"; fos.write(s.getBytes()); //关闭流(一定要记得关闭) fos.close(); System.out.println("程序结束"); } }
运行结果:
续写文件:
import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; public class Demo2 { public static void main(String[] args) throws Exception { FileOutputStream fos = new FileOutputStream("out.txt",true); //方法二 //File file = new File("out.txt"); //FileOutputStream fos = new FileOutputStream(file,true); String s = "\n人生苦短,我学Java"; fos.write(s.getBytes()); fos.close(); System.out.println("程序结束"); } }
运行结果:
2.3 字节输入流
2.3.1 字节输入流InputStream
通过字节输出流,我们可以把内存中的数据写出到文件中,那如何想把文件中的数据读到内存中,可以通过InputStream可以实现。
InputStream是抽象类,是所有字节输入流类的超类,该类定义了字节输入流的基本共性功能方法。
主要方法:
方法 方法声明 功能描述 public int read() 从输入流中读取一个8位的字节,把它转化为0~255之间的整数,并返回这一整数,但没有可用字节时,将返回-1 public int read(byte b[]) 读取一定量的字节数,并存储到字节数组中,返回读取到的字节数
public int read(byte b[],int off, int len) 将输入流中最多len个数据字节读入byte数组中 public void close() 关闭此输入流并释放与该流关联的所有数据系统 int read():读取一个字节并返回,没有字节返回-1.
int read(byte[]):将读取到的数据存入到数组中,并返回读取到的个数
2.3.2 FileInputStream类
InputStream有很多子类,其中子类FileInputStream可用来读取文件内容。
FileInputStream 从文件系统中的某个文件中获得输入字节。
构造方法:
构造方法 方法声明 功能描述 public FileInputStream(String name) 通过打开一个到实际文件连接来创建FileInputStream,该文件通过文件系统中路径名name指定。 public FileInputStream(File file) 通过打开一个到实际文件连接来创建FileInputStream,该文件通过文件系统中的File对象file指定。
基本读取文件数据:
代码一:(读取单个字符)
import java.io.FileInputStream; public class Demo1 { public static void main(String[] args) throws Exception { //创建一个文件输入流来读取文件 //注:读取文件时,必须保证文件在相应目录存在并且是可读的,若不存在,则会抛出异常 FileInputStream fis = new FileInputStream("text"); //定义以个int类型的变量 int b = 0; //使用循环,读取文件所有内容 //通过循环来判断,当返回为-1时结束循环 while((b = fis.read()) != -1){ System.out.println((char)b); } //关闭流 fis.close(); System.out.println("程序结束"); } }
运行结果:
代码二:(一次获取一个数组)/(数组缓冲区)
1.int read(byte[])的使用:
import java.io.FileInputStream; import java.util.Arrays; public class Demo2 { public static void main(String[] args) throws Exception { FileInputStream fis = new FileInputStream("text"); byte[] bytes = new byte[2]; //将读取到的数据存入到数组中,并返回读取到的个数 int count = fis.read(bytes); System.out.println(count + " " + Arrays.toString(bytes)); System.out.println(fis.read(bytes) + " " + Arrays.toString(bytes)); System.out.println(fis.read(bytes) + " " + Arrays.toString(bytes)); System.out.println(fis.read(bytes) + " " + Arrays.toString(bytes)); } }
运行结果:
2.循环读取:
import java.io.FileInputStream; import java.util.Arrays; public class Demo2 { public static void main(String[] args) throws Exception { FileInputStream fis = new FileInputStream("text"); byte[] bytes = new byte[2]; //将读取到的数据存入到数组中,并返回读取到的个数 // int count = fis.read(bytes); // System.out.println(count + " " + Arrays.toString(bytes)); // // System.out.println(fis.read(bytes) + " " + Arrays.toString(bytes)); // System.out.println(fis.read(bytes) + " " + Arrays.toString(bytes)); // System.out.println(fis.read(bytes) + " " + Arrays.toString(bytes)); int count = 0; while ((count = fis.read(bytes)) != -1) { System.out.println(Arrays.toString(bytes)); } //关闭流 fis.close(); System.out.println("程序结束"); } }
运行结果:
问题:最后一行的数组的第二个数并未被重新赋值
解决:
import java.io.FileInputStream; import java.util.Arrays; public class Demo2 { public static void main(String[] args) throws Exception { FileInputStream fis = new FileInputStream("text"); byte[] bytes = new byte[2]; int count = 0; while ((count = fis.read(bytes)) != -1) { // System.out.println(Arrays.toString(bytes)); //第一次count:2 //第二次count:2 //第三次count:1 //键byte数组转化为字符串,并从索引位置0开始读取count个数 String s = new String(bytes,0,count); System.out.println(s); } } }
运行结果:
2.3.3 字节流练习
1.复制文件
思路:读取一个已有的数据,并将这些读到的数据写入到另一个文件中。
需要用到的流:
- 输入流:FileInputStream
- 输出流:FileOutputStream
将out.text复制一份为out2.txt(out2.txt并未创建):
代码一:单字符复制
import java.io.FileInputStream; import java.io.FileOutputStream; public class Demo3 { public static void main(String[] args) throws Exception { FileInputStream fis = new FileInputStream("out.txt"); FileOutputStream fos = new FileOutputStream("out2.txt"); int n = 0; while((n = fis.read())!= -1){ fos.write(n); } //关闭流,后打开的先关闭 fos.close(); fis.close(); System.out.println("程序结束"); } }
运行结果:
代码二:(多字符复制)
import java.io.FileInputStream; import java.io.FileOutputStream; /** * 多字符复制 * 边读取边写入,效率高 */ public class Demo2 { public static void main(String[] args) throws Exception { FileInputStream fis = new FileInputStream("out.txt"); FileOutputStream fos = new FileOutputStream("out3.txt"); byte[] bytes = new byte[1024]; int count = 0; while ((count = fis.read(bytes)) != -1) { //只写读取到的数据 fos.write(bytes,0,count); } //关闭流,后打开的先关闭 fos.close(); fis.close(); System.out.println("复制成功"); } }
运行结果:
2.拷贝指定路径的文件到指定路径下
代码:
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.Scanner; /** * 在控制台录入文件的路径,将文件拷贝到当前项目下 * 分析: * 1. 定义方法对键盘录入的路径进行判断,如果是文件就返回 * 2. 在主方法中接收该文件 * 3. 读和写该文件 */ public class Demo { public static void main(String[] args) throws Exception { File file = getFile(); FileInputStream fis = new FileInputStream(file); //获取路径文件名,将其输出到当前路径中 FileOutputStream fos = new FileOutputStream(file.getName()); byte[] bytes = new byte[1024]; int count = 0; while ((count = fis.read(bytes)) != -1) { fos.write(bytes, 0, count); } fos.close(); fis.close(); System.out.println("复制完毕"); } /** * 获取文件 * * @return File */ public static File getFile() { Scanner sc = new Scanner(System.in); while (true) { System.out.print("请输入一个文件名的路径:"); String path = sc.next();// 封装成File对象,并对其进行判断 File file = new File(path); if (!file.exists()) { System.out.println("输入的路径不存在"); } else if (file.isDirectory()) { System.out.println("输入的路径必须是文件"); } else { return file; } } } }
运行结果:
3.统计一个文件中字母或数字出现的个数
代码1 先读取再统计:
/** * 统计一个文件中字母或数字出现的个数 * 实现思路: * 1.读取文件,将文件内容保存到String类型的变量中 * 2.使用Map集合的特性,完成统计功能 */ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.Scanner; import java.util.TreeMap; public class Demo1 { public static void main(String[] args) throws IOException { //写入文件 write(); //统计一个文件中字母或数字出现的个数 //1.读取文件,将文件内容保存到String类型的变量中 FileInputStream fis = new FileInputStream("D:\\学习\\java\\笔记1\\src\\笔记7\\IO\\demo03_字节流练习\\统计一个文件中出现字母或数字出现的个数\\统计字符个数.txt"); //将读取到的内容读取到数组中,之后在遍历 byte[] bytes = new byte[10]; int count = 0; //将读取到的数据封装为String类型 StringBuffer sb = new StringBuffer(); while ((count = fis.read(bytes)) != -1) { sb.append(new String(bytes, 0, count)); } TreeMap
treeMap = new TreeMap<>(); for (char c : sb.toString().toCharArray()) { //进行统计 //Map集合方法:public boolean containsKey(Object key) 是否包含指定的key treeMap.put(c, treeMap.containsKey(c) ? treeMap.get(c) + 1 : 1); } System.out.println(sb.toString()); System.out.println(treeMap); } public static void write() throws IOException { //将数据写入文件 Scanner sc = new Scanner(System.in); FileOutputStream fos = new FileOutputStream("D:\\学习\\java\\笔记1\\src\\笔记7\\IO\\demo03_字节流练习\\统计一个文件中出现字母或数字出现的个数\\统计字符个数.txt"); //输入字母数据 System.out.println("输入要写入文本的数据:"); String s = sc.next(); if (s.matches("[a-zA-Z0-9]+[a-zA-Z0-9]+[a-zA-Z0-9]+")) { fos.write(s.getBytes()); } else { System.out.println("您只能输入字母或数字"); } fos.close(); } } 运行结果:
代码2 边读取边统计:
public static void main(String[] args) throws IOException { TreeMap
treeMap = new TreeMap<>(); FileInputStream fis = new FileInputStream("D:\\学习\\java\\笔记1\\src\\笔记7\\IO\\demo03_字节流练习\\统计一个文件中出现字母或数字出现的个数\\统计字符个数.txt"); int n = 0; while ((n = fis.read()) != -1) { char c = (char) n; //Map集合方法:public boolean containsKey(Object key) 是否包含指定的key treeMap.put(c, treeMap.containsKey(c) ? treeMap.get(c) + 1 : 1); } System.out.println(treeMap); } 运行结果:
4.将集合中的数据存入文件中,再读取文件的数据存入集合中
{摩卡:30,卡布奇诺:27,拿铁:27,香草拿铁:30}
- 存入文件的格式
摩卡=30
卡布奇诺=27
拿铁=27
香草拿铁=30
代码:
public static void main(String[] args) throws IOException { Map
map = new LinkedHashMap<>(); map.put("摩卡",30); map.put("卡布奇诺",27); map.put("拿铁",27); map.put("香草拿铁",30); FileOutputStream fos = new FileOutputStream("3.txt"); for (String key : map.keySet()) { fos.write(key.getBytes()); fos.write("=".getBytes()); fos.write(map.get(key).toString().getBytes());//将Integer型转化为byte数组 fos.write("\r\n".getBytes());//换行 } fos.close(); System.out.println("存入成功"); } 运行结果:
2.将刚刚保存文件中的数据读取到集合中
代码:
public static void main(String[] args) throws IOException { FileInputStream fis = new FileInputStream("3.txt"); StringBuffer sb = new StringBuffer(); byte[] bytes = new byte[1024]; int count = 0; while((count = fis.read(bytes))!=-1){ sb.append(new String(bytes,0,count)); } fis.close(); System.out.println("读取完毕"); String[] strint = sb.toString().split("\r\n"); Map
map = new LinkedHashMap<>(); for (String str : strint) { String[] s = str.split("="); //public static int parseInt(String s) 将字符串强制转化为Integer map.put(s[0],Integer.parseInt(s[1])); } System.out.println(map); }
3.I/O流异常处理
3.1 正常情况下的处理方式
一般情况下,我们在IO流中,是这样处理关闭的
public static void main(String[] args) { FileInputStream fis = null; try { fis = new FileInputStream("text"); int n = 0; while ((n = fis.read()) != -1) { System.out.print((char) n); } System.out.println(); // 1处 若此处出现异常,则不会运行以下的fis.close(); fis.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }
这样处理有问题,如果在1这个位置上发生了异常,那么close()方法就执行不到了,会导致流没有正常被关闭,所以将关闭的方法放到finally代码块中
public static void main(String[] args) { FileInputStream fis = null; try { // 1 fis = new FileInputStream("text"); int n = 0; while ((n = fis.read()) != -1) { System.out.print((char) n); } System.out.println(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { fis.close(); } }
finally代码块无论是否发生异常都会执行,看着这个代码感觉完美,但是还是有问题的,如果再1的位置上发生了一次,那么 fis = new FileInputStream("text");这句代码是无法执行,而在finally代码块中有使用了fis对象,此时fis是null的,所以这里还有可能发生一个空指针异常,
再次修改代码,进行非空判断:
public static void main(String[] args) { FileInputStream fis = null; try { fis = new FileInputStream("text"); int n = 0; while ((n = fis.read()) != -1) { System.out.print((char) n); } System.out.println(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { if(fis != null){ try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } }
运行结果:
3.2 JDK7资源自动关闭
AutoCloseable接口对JDK7新添加的带资源的try语句提供了支持,这种try(try-with-resources)语句可以很容易地关闭在try-catch语句块中使用的资源。
在JDK7中只要实现了AutoCloseable或Closeable接口的类或接口,都可以使用try-with-resource来实现异常处理和资源关闭
- 在JDK7以前,程序中使用的资源需要被明确地关闭,这个体验有点繁琐。
- try语句块中有2个地方能抛出异常,finally语句块中有一个地方会能出异常。不论try语句块中是否有异常抛出,finally语句块始终会被执行。这意味着,无论try语句块中发生什么,InputStream 都会被关闭,或者说都会试图被关闭。
- 如果关闭失败,InputStream.close()方法也可能会抛出异常。
在JDK7中,对于上面的例子可以用try-with-resource 结构这样写
public static void main(String[] args) { try(FileInputStream fis = new FileInputStream("text")) { int n = 0; while ((n = fis.read()) != -1) { System.out.print((char) n); } System.out.println(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
运行结果:
注意方法第二行
try(FileInputStream fis = new FileInputStream("text")){
- 这就是try-with-resource结构的用法。FileInputStream类型变量就在try关键字后面的括号中声明。而且一个FileInputStream 类型被实例化并被赋给了这个变量。
- 关于带资源的try语句的3个关键点
1. 由带资源的try语句管理的资源必须是实现了AutoCloseable接口的类的对象。
2 .在try代码中声明的资源被隐式声明为fianlly
3. 通过使用分号分隔每个声明可以管理多个资源。
4. 所声明资源的作用域被限制在带资源的try语句中。
3. 带资源的try语句的主要优点是:
1. 当try代码块结束时,资源(在此时流)会被自动关闭。因此,不太可能会忘记关闭流。
2.使有带资源的try语句,通常可以使源代码更短,更清晰,更容易维护。
使用多个资源:
public class Demo2 { public static void main(String[] args) { try(FileInputStream fis = new FileInputStream("text"); FileOutputStream fos = new FileOutputStream("text",true)){ } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
4.字符流
4.1 编码
4.1.1默认编码写入和读取
学习字符流之前,我们先来研究一下文件编码:
通过以下程序读取带有中文件的文件:
public static void main(String[] args) throws IOException { //给文件中写入中文 writeText(); //读取文件中的中文 readText(); } public static void writeText() throws IOException { FileOutputStream fos = new FileOutputStream("1.txt"); fos.write("你好world(世界)".getBytes()); fos.close(); } public static void readText() throws IOException { FileInputStream fis = new FileInputStream("1.txt"); int n = 0; while((n = fis.read())!=-1){ System.out.print(n); } System.out.println(); fis.close(); }
运行结果:
上面程序在读取含有中文的文件时,我们并没有看到具体的中文,而是看到一些数字,这是什么原因呢?
既然看不到中文,那么我们如何对其中的中文做处理呢?要解决这个问题,我们必须研究下字符的编码过程。
4.1.2 指定编码写入和读取
Java的IO流中按字节分就有字节流和字符流之分,字节流是按字节为单位来操作的,而字符流当然是按字符为单位来操作的
字节流一般是用来操作一些二进制文件,例如MP3文件,JPG等等。
字符流一般是用来操作一些文本文件。
编码:将源对象内容按照一种标准转换为一种标准格式内容。
String-->getBytes()//使用平台默认的字符集
getBytes(String charset)//指定编码方式
解码:使用和编码相同的标准将编码内容还原为最初的对象内容。
String-->构造方法:String(byte[] b):使用平台默认字符集解码
String(byte[] b,String charset):指定解码方式
对于文本文件,写入和读取使用相同的"编码方式",就会避免乱码的情况
用指定的编码进行读取数据,是可以正确显示内容的:
public static void main(String[] args) throws IOException { //写入文件 FileOutputStream fos = new FileOutputStream("2.txt"); //使用String的 public byte[] getBytes(String charsetName) 方法实现指定编码写入 byte[] bytes1 = "你好世界".getBytes("UTF-8"); System.out.println("数组长度: " + bytes1.length); System.out.println("数组内容: " + Arrays.toString(bytes1)); fos.write(bytes1); fos.close(); System.out.println("写入完毕"); //读取文件 FileInputStream fis = new FileInputStream("2.txt"); byte[] bytes2 = new byte[bytes1.length];//不要随意修改数组的大小 int n = fis.read(bytes2); System.out.println("读取数组的字节: " + Arrays.toString(bytes2)); //解码 String s = new String(bytes2, "UTF-8"); System.out.println("读取文件内容: " + s); }
运行结果:
4.1.3 字符编码表
我们知道计算机底层数据存储的都是二进制数据,而我们生活中的各种各样的数据,如何才能和计算机中存储的二进制数据对应起来呢?
这时西方国家就把每一个字符和一个整数对应起来,就形成了一张编码表,西方国家的编码表就ASCII表。其中就是各种英文字符对应的编码。
编码表:其实就是生活中字符和计算机二进制的对应关系表。
- ASCII:一个字节中的7位就可以表示。对应的字节都是正数。0-xxxxxxx
- iso-8859-1:拉丁码表 latin,用了一个字节用的8位。1-xxxxxxx 负数。
- GB2312:简体中文码表。包含6000-7000中文和符号。用两个字节表示。两个字节第一个字节是负数,第二个字节可能是正数
- GBK:目前最常用的中文码表,2万的中文和符号。用两个字节表示,其中的一部分文字,第一个字节开头是1,第二字节开头是0
- GB18030:最新的中文码表,目前还没有正式使用。
- unicode:国际标准码表:无论是什么文字,都用两个字节存储。
- Java中的char类型用的就是这个码表。char c = 'a';占两个字节。
- Java中的字符串是按照系统默认码表来解析的。简体中文版默认的码表是GBK。
- UTF-8:基于unicode,一个字节就可以存储数据,不要用两个字节存储,而且这个码表更加的标准化,在每一个字节头加入了编码信息(后期到api中查找)。
能识别中文的码表:GBK、UTF-8;正因为识别中文码表不唯一,涉及到了编码解码问题。
对于我们开发而言,常见的编码为:GBK、UTF-8、ISO-8859-1
文字 ---> (数组):“abc”.getBytes()
(数组) ---> 文字:解码。 byte[] b={97,98,99} new String(b)
问题:
假设使用的环境是UTF-8,中文字符占3个字节,非中文占一个字节
例如:"abc你好"
当我们以每四个字节读取文件时,此时会读到 "abc" + "你"的一半,此时就会产生乱码。
byte[] b = new btye[4];
inputStream.read(b);// 出现乱码
所以可以使用字符流来解决根源问题
4.2 字符输入流
1.字符流概述
对文本内容进行读取,如果想从文件中直接读取字符便可以使用字符输入流FileReader,通过此流可以从关联的文件中读取一个或一组字符。
2.什么是文本文件
计算机的文件场被分为文本文件和二进制文件两大类:
可以认为:所有可以用记事本打开并且可以看到懂字符内容的文件称为文本文
件,反之则是二进制文件。
计算机中所有的文件都是二进制文件,文本文件只是一种特殊的存在,如果二
进制文件的内容恰好能被正常解析成字符时,则改二进制文件就可以称为文本 文件。
在有些情况下,文本文件使用了错误的字符集打开,会生成乱码,所以如果想
正常查看文本文件,必须在打开文件时使用与保存文件时相同的字符集。
4.2.1 Reader
上述程序中我们读取拥有中文的文件时,使用的字节流在读取,那么我们读取到的都是一个一个字节。只要把这些字节去查阅对应的编码表,就能够得到与之对应的字符。API中是否给我们已经提供了读取相应字符的功能流对象,Reader,读取字符流的抽象超类。
Reader类方法 方法声明 功能描述 public int read() 读取单个字符并返回(没有可读字节时,将返回-1) public int read(char cbuf[]) 将字符读入数组,返回读取字符个数。(没有可读字节时,将返回-1) public void close() 关闭该流并释放与之关联的所有资源。 4.2.2 FileReader类
要读取字符数据,请考虑使用 FileReader。
FileReader构造方法 方法声明 功能描述 public FileReader(String fileName) 在给定从中读取数据的文件名的情况下创建一个新 FileReader。 public FileReader(File file) 在给定从中读取数据的 File 的情况下创建一个新 FileReader 需要注意的是:FileReader类没有特有的方法,所有方法均继承自父类
4.2.3 使用FileReader读取包含中文的文件
代码一(读取单字符):
public static void main(String[] args) throws IOException { FileReader fr = new FileReader("reader.txt"); //读取单字符 System.out.println("-----读取单字符-----"); int n = 0; while((n = fr.read())!= -1){ System.out.println(n +" = "+(char)n); } //关闭流 fr.close(); }
代码二(读取多字符):
public static void main(String[] args) throws IOException { FileReader fr = new FileReader("reader.txt"); //读取多字符 System.out.println("-----读取多字符-----"); char[] chars = new char[10]; int count = 0; while((count = fr.read(chars))!=-1){ System.out.print(new String(chars,0,count)); } System.out.print() //关闭流 fr.close(); }
4.3 字符输出流
4.3.1 Writer类
既然有专门用于读取字符的流对象,那么肯定也有写的字符流对象,Writer类,Writer是写入字符流的抽象类。其中描述了相应的写的动作。
Writer构造方法 方法声明 功能描述 protected Writer() 创建一个新的字符流 writer,其关键部分将同步 writer 自身。 protected Writer(Object lock) 创建一个新的字符流 writer,其关键部分将同步给定的对象。
Writer方法 方法声明 功能描述 abstract public void flush() 刷新该流的缓冲。 public void write(int c) 写入单个字符。 public void write(char cbuf[]) 写入字符数组。 abstract public void write(char cbuf[], int off, int len) 写入字符数组的某一部分。 public void write(String str) 写入字符串. public void write(String str, int off, int len) 写入字符串的某一部分。 abstract public void close() 关闭此流,但要先刷新它。 4.3.2 FileWriter类
FileOutputStream 用于写入诸如图像数据之类的原始字节的流。要写入字符流,请考虑使用 FileWriter。
构造方法:
FileWriter构造方法 方法声明 功能描述 public FileWriter(String fileName) 根据给定的文件名构造一个 FileWriter 对象。 public FileWriter(String fileName, boolean append) 根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象。 public FileWriter(File file) 根据给定的 File 对象构造一个 FileWriter 对象。 public FileWriter(File file, boolean append) 根据给定的 File 对象以及指示是否附加写入数据的 boolean 值来构造一个 FileWriter 对象。 4.3.3flush()和close()的区别?
- flush():将流中的缓冲区缓冲的数据刷新到目的地中,刷新后,流还可以继续使用。
- close():关闭资源,但在关闭前会将缓冲区中的数据先刷新到目的地,否则丢失数据,然后在关闭流。流不可以使用。如果写入数据多,一定要一边写一边刷新,最后一次可以不刷新,由close完成刷新并关闭。
4.3.4FileWriter写入中文到文件中
public static void main(String[] args) throws IOException { FileWriter fw = new FileWriter("writer.txt"); //写入单字符 fw.write('你'); fw.flush(); //刷新 fw.write('好'); fw.flush(); //刷新 fw.write('吗'); fw.flush(); //刷新 //写入多个字符 char[] chars = {'?','我','很','好','!'}; fw.write(chars); fw.flush(); //刷新 //写入字符串 fw.write("\r\n"); fw.flush(); //刷新 fw.write("轻轻的我走了,\r\n"); fw.flush(); //刷新 fw.write("正如我轻轻的来;\r\n"); fw.flush(); //刷新 fw.write("我轻轻的招手,\r\n"); fw.flush(); //刷新 fw.write("作别西天的云彩"); //关闭流 fw.close(); System.out.println("写入完毕"); }
4.3.5 字符流练习题
复制文本文件
题目:将writer.txt复制一份
代码一(边读取边输出):
public static void main(String[] args) throws IOException { FileReader fr = new FileReader("writer.txt"); FileWriter fw = new FileWriter("writerCopy.txt"); //边读取边输出 int n = 0; while ((n = fr.read()) != -1) { fw.write(n); fw.flush();//边输出边刷新 } //关闭流,后打开先关闭 fw.close(); fr.close(); System.out.println("复制完毕"); }
代码二(先读取再输出):
public static void main(String[] args) throws IOException { FileReader fr = new FileReader("writer.txt"); FileWriter fw = new FileWriter("writerCopy2.txt"); //先读取在输出 StringBuffer sb = new StringBuffer(); char[] chars = new char[10]; int count = 0; while ((count = fr.read(chars)) != -1) { sb.append(new String(chars,0,count)); } fw.write(sb.toString()); fw.flush(); //关闭流,后打开先关闭 fw.close(); fr.close(); System.out.println("复制完毕"); }
5.转换流
5.1 OutputStreamWriter
OutputStreamWriter是Writer的子类
OutputStreamWriter 是字符流通向字节流的桥梁,可使用指定的字符编码表,将要写入流中的字符编码成字节。
它的作用的就是,将字符串按照指定的编码表转成字节,再使用字节流将这些字节写出去。
构造方法:
OutputStreamWriter构造方法 方法声明 功能描述 public OutputStreamWriter(OutputStream out) 创建使用默认字符编码的 OutputStreamWriter。 public OutputStreamWriter(OutputStream out, String charsetName) 创建使用指定字符集的 OutputStreamWriter 示例:
public static void main(String[] args) throws IOException { // 创建与文件关联的字节输出流对象 FileOutputStream fos = new FileOutputStream("4.txt"); // 创建可以把字符转成字节的转换流对象,并指定编码 OutputStreamWriter osw = new OutputStreamWriter(fos, "utf-8"); // 调用转换流,把文字写出去,其实是写到转换流的缓冲区中 osw.write("你好");// 写入缓冲区。 //关闭流 osw.close(); fos.close(); }
5.2 InputStreamReader
InputStreamReader是Reader的子类
InputStreamReader 是字节流通向字符流的桥梁:它使用指定的字符编码表读取字节并将其解码为字符。
可以通过构造方法指定字符集:
InputStreamReader构造方法 方法声明 功能描述 public InputStreamReader(InputStream in) 创建一个使用默认字符集的 InputStreamReader。 public InputStreamReader(InputStream in, String charsetName) 创建使用指定字符集的 InputStreamReader。 示例:
public static void main(String[] args) throws IOException { // 创建读取文件的字节流对象 InputStream in = new FileInputStream("4.txt"); // 创建转换流对象 // InputStreamReader isr = new // InputStreamReader(in);这样创建对象,会用本地默认码表读取,将会发生错误解码的错误 InputStreamReader isr = new InputStreamReader(in, "utf-8"); // 使用转换流去读字节流中的字节 int ch = 0; while ((ch = isr.read()) != -1) { System.out.println((char) ch); } // 关闭流 isr.close(); in.close(); }
6. 缓冲流
在使用流读取数据量大的文件时,读取的速度会很慢,影响我们程序的效率,那么想提高速度,怎么办?
Java中提高了一套缓冲流,可以提高IO流的读写速度
缓冲流,根据流的分类分类字节缓冲流与字符缓冲流。
在以后的代码中,最好都用缓冲流
6.1 字节缓冲流
字节缓冲流根据流的方向,有2个:
- 写入数据到流中,字节缓冲输出流 BufferedOutputStream
- 读取流中的数据,字节缓冲输入流 BufferedInputStream
它们的内部都包含了一个缓冲区,通过缓冲区读写,就可以提高了IO流的读写速度
6.1.1 字节缓冲输出流BufferedOutputStream
BufferedOutputStream为OutputStream子类,继承OutputStream的所有方法
通过字节缓冲流,进行文件的读写操作,写数据到文件中
BufferedOutputStream构造方法 方法声明 功能描述 public BufferedOutputStream(OutputStream out) 创建一个新的缓冲输出流,以将数据写入指定的底层输出流。 public BufferedOutputStream(OutputStream out, int size)创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流。 举例代码:
public static void main(String[] args) throws IOException { // 创建基本的字节输出流 FileOutputStream fos = new FileOutputStream("5.txt"); // 使用高效的流,把基本的流进行封装,实现速度的提升 BufferedOutputStream bos = new BufferedOutputStream(fos); //写数据 bos.write("Hello world.Hello Java.".getBytes()); //关闭流 bos.close(); fos.close(); //使用匿名对象创建 //BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("5.txt")); }
6.1.2 字节缓冲输入流BufferedInputStream
BufferedInputStream为InputStream子类,继承InputStream的所有方法
BufferedInputStream构造方法 方法声明 功能描述 public BufferedInputStream(InputStream in) 创建一个 BufferedInputStream
并保存其参数,即输入流in
,以便将来使用。public BufferedInputStream(InputStream in, int size) 创建具有指定缓冲区大小的 BufferedInputStream
并保存其参数,即输入流in
,以便将来使用。代码:
public static void main(String[] args) throws IOException { // 1. 创建缓冲流对象 FileInputStream fis = new FileInputStream("5.txt"); // 把基本的流包装成高效的流 BufferedInputStream bis = new BufferedInputStream(fis); //读取数据 int count = 0; byte[] bytes = new byte[10]; while((count = bis.read(bytes))!=-1){ //打印 System.out.print(new String(bytes,0,count)); } System.out.println(); //关闭流 bis.close(); fis.close(); }
6.1.3 缓冲流效率的对比
使用四种操作流的方式来拷贝数据,查看其效率
字节流四种读写方式效率的对比:
1.基本字节流:
FileOutputStream:
FileInputStream:
1).一次读写一个字节: m1(); 54986 毫秒
2).一次读写一个字节数组: m2(); 97 毫秒
2.缓冲字节流:
BufferedOutputStream:
BufferedInputStream:
3).一次读写一个字节: m3(); 666 毫秒
4).一次读写一个字节数组: m4(); 38 毫秒
代码如下:
public class Demo { public static void main(String[] args) throws IOException { long start = System.currentTimeMillis(); // method1();//54986 毫秒 // method2();//97 毫秒 // method3();//666毫秒 method4();// 38 毫秒 long end = System.currentTimeMillis(); System.out.println("执行时间:" + (end - start) + " 毫秒"); } // 基本流:一次读写一个字节 private static void m1() throws IOException { // 1.输入流: FileInputStream in = new FileInputStream("C:\\aaa\\1.txt"); // 2.输出流 FileOutputStream out = new FileOutputStream("copy1.txt"); // 一次读写一个字节 int n = 0; while ((n = in.read()) != -1) { out.write(n); } // 释放资源 in.close(); out.close(); } // 基本流:一次读写一个字节数组 private static void method2() throws IOException { // 1.输入流: FileInputStream in = new FileInputStream("C:\\aaa\\1.txt"); // 2.输出流 FileOutputStream out = new FileOutputStream("copy2.txt"); // 一次读写一个字节数组 byte[] byteArray = new byte[1024]; int n = 0; while ((n = in.read(byteArray)) != -1) { out.write(byteArray, 0, n); } in.close(); out.close(); } // 缓冲流:一次读写一个字节 private static void method3() throws IOException { // 1.缓冲输入流 BufferedInputStream bufIn = new BufferedInputStream(new FileInputStream("C:\\aaa\\1.txt")); // 2.缓冲输出流 BufferedOutputStream bufOut = new BufferedOutputStream(new FileOutputStream("copy3.txt")); // 一次读写一个字节 int n = 0; while ((n = bufIn.read()) != -1) { bufOut.write(n); } bufIn.close(); bufOut.close(); } // 缓冲流:一次读写一个字节数组 private static void method4() throws IOException { // 1.缓冲输入流 BufferedInputStream bufIn = new BufferedInputStream(new FileInputStream("C:\\aaa\\1.txt")); // 2.缓冲输出流 BufferedOutputStream bufOut = new BufferedOutputStream(new FileOutputStream("copy4.txt")); // 一次读写一个字节数组 byte[] byteArray = new byte[1024]; int n = 0; while ((n = bufIn.read(byteArray)) != -1) { bufOut.write(byteArray, 0, n); } bufIn.close(); bufOut.close(); } }
6.2 字符缓冲流
- 字符缓冲输入流 BufferedReader
- 字符缓冲输出流 BufferedWriter
完成文本数据的高效的写入与读取的操作
6.2.1 字符缓冲输出流BufferedWriter
BufferedWriter 为 Writer 子类
将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
BufferedWriter构造方法 方法声明 功能描述 public BufferedWriter(Writer out) 创建一个使用默认大小输出缓冲区的缓冲字符输出流。 public BufferedWriter(Writer out,int size) 创建一个使用给定大小输出缓冲区的新缓冲字符输出流。
BufferedWriter特有方法 方法声明 功能描述 public void newLine() 写入一个行分隔符。(其实就是换行) public static void main(String[] args) throws IOException { // 基本字符输出流 FileWriter fw = new FileWriter("6.txt"); // 把基本的流进行包装 BufferedWriter bw = new BufferedWriter(fw); //写入数据 bw.write("hello world"); bw.newLine();//换行 bw.write("你好世界"); //关闭流 bw.close(); fw.close(); }
6.2.2 字符缓冲输入流BufferedReader
BufferedReader为Reader子类
从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
BufferedReader构造方法 方法声明 功能描述 public BufferedReader(Reader in) 创建一个使用默认大小输入缓冲区的缓冲字符输入流。 public BufferedReader(Reader in, int sz) 创建一个使用指定大小输入缓冲区的缓冲字符输入流。
BufferedReader特有方法 方法声明 功能描述 public String readLine() 读取一个文本行。(一次读取一行数据,读取不到返回null) 代码:
public static void main(String[] args) throws IOException { // 1,创建流 BufferedReader br = new BufferedReader(new FileReader("6.txt")); // 2,读数据 System.out.println(br.readLine());//一次读一行数据 //读取剩下的数据 char[] chars = new char[10]; int count = 0; while ((count = br.read(chars)) != -1) { System.out.print(new String(chars,0,count)); } System.out.println(); //关闭流 br.close(); }
6.2.3 练习
1.使用字符缓冲流优化 数据集合 互转
代码:
public static void main(String[] args) throws IOException { Map
map = new LinkedHashMap<>(); map.put("摩卡",30); map.put("卡布奇诺",27); map.put("拿铁",27); map.put("香草拿铁",30); //写入数据 BufferedWriter bw = new BufferedWriter(new FileWriter("7.txt")); for (String key : map.keySet()) { bw.write(key+"="+map.get(key)); bw.newLine(); } bw.close(); //读取数据 BufferedReader br = new BufferedReader(new FileReader("7.txt")); String str = null; Map map2 = new LinkedHashMap<>(); while((str = br.readLine())!=null){ //System.out.println(str); String[] ss = str.split("="); map2.put(ss[0],Integer.parseInt(ss[1])); } System.out.println(map2); br.close(); System.out.println("程序结束"); } 2.使用字符缓冲流拷贝文件
拷贝夜的命名术.txt:
代码:
import java.io.*; public class Demo1 { public static void main(String[] args) throws IOException { m1(); m2(); } //使用缓冲流:一次读取一个字符 public static void m1() throws IOException { //创建对象 BufferedReader br = new BufferedReader(new FileReader("夜的命名术.txt")); BufferedWriter bw = new BufferedWriter(new FileWriter("夜的命名术1.txt")); //读写数据 int n = 0; while ((n = br.read()) != -1) { bw.write(n); } //关闭流 br.close(); bw.close(); System.out.println("m1拷贝成功"); } //使用缓冲流:一次读取一个字符数组 public static void m2() throws IOException { //创建对象 BufferedReader br = new BufferedReader(new FileReader("夜的命名术.txt")); BufferedWriter bw = new BufferedWriter(new FileWriter("夜的命名术2.txt")); //读写数据 char[] chars = new char[1024]; int count = 0; while ((count = br.read(chars)) != -1) { bw.write(chars); } //关闭流 br.close(); bw.close(); System.out.println("m2拷贝成功"); } }
7.对象序列化流
有时希望将以对象方式存在于内存中的数据存储至文件(持久化到文件),需要时再将其从文件中读出还原为对象,或者在网络上传送对象,这时可以使用Java提供的对象流ObjectInputStream和ObjectOutputStream。
序列化:是指将一个"对象(包含属性值)"存储到一个文件中,或者通过网络进行传输
类介绍:ObjectInputStream
构造方法:
ObjectInputStream构造方法 方法声明 功能描述 ObjectOutputStream(OutputStream out) 创建写入指定 OutputStream 的 ObjectOutputStream。 序列化的方法
ObjectInputStream序列化方法 方法声明 功能描述 void writeObject(Object obj) 将指定的对象写入 ObjectOutputStream public void close() 关闭输出流。 注意:当某个对象需要被"序列化"时,此类必须实现:Serializable(接口)
在Serializable接口中,没有任何方法,这种接口叫:标记接口;它类似于一个标记,某个类如果实现了这样的接口,表示这个类就具有了某种权限(功能)
反序列化:是指将一个文本文件转成一个Java对象
类介绍:ObjectInputStream
构造方法:
ObjectInputStream构造方法 方法声明 功能描述 ObjectInputStream(InputStream in) 创建写入指定 InputStream 的 ObjectInputStream。 反序列化的方法
方法声明 功能描述 Object readObject() 从 ObjectInputStream 读取对象。 public void close() 关闭输入流。 例:将一个Student对象持久化到文件,并从文件读出。
代码:
import java.io.*; public class Demo { public static void main(String[] args) throws IOException, ClassNotFoundException { //创建类对象 Student student = new Student("张三", 15); //序列化 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("Student")); //写入对象 oos.writeObject(student); oos.close(); //反序列化 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("Student")); Object o = ois.readObject(); Student s = (Student) o; System.out.println(s); } } //需要实现Serializable class Student implements Serializable { private String name; private int age; public Student(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
8.打印流
输出流在通过write()方法写数据时,只能输出字节或字符串类型的数据,如果希望输出其他类型的数据,例如输出一个基本数据类型int的值9,此时需要将数据线转换成字符串再上传,为此,Java提供了PrintStream
PrintStream打印流是输出信息最方便的类,主要包含字节打印流(PrintStream) 和字符打印流(PrintWriter) . 打印流提供了非常方便的打印功能,可以打印任何的数据类型,例如: 小数、整数、字符串等等。
8.1 PrintStream
PrintStream提供了大量重载的print()和println()方法,可以打印各种数据值。
构造方法:
PrintStream(File file)
创建具有指定文件且不带自动行刷新的新打印流。PrintStream(File file, String csn)
创建具有指定文件名称和字符集且不带自动行刷新的新打印流。PrintStream(OutputStream out)
创建新的打印流。PrintStream(OutputStream out, boolean autoFlush)
创建新的打印流。PrintStream(OutputStream out, boolean autoFlush, String encoding)
创建新的打印流。PrintStream(String fileName)
创建具有指定文件名称且不带自动行刷新的新打印流。PrintStream(String fileName, String csn)
创建具有指定文件名称和字符集且不带自动行刷新的新打印流。常用方法:
void
close()
关闭流。
voi
print(boolean b)
打印 boolean 值。void
print(char c)
打印字符。void
print(char[] s)
打印字符数组。void
print(double d)
打印双精度浮点数。void
print(float f)
打印浮点数。void
print(int i)
打印整数。void
print(long l)
打印 long 整数。void
print(Object obj)
打印对象。void
print(String s)
打印字符串。println()方法在print()的基础上,每次输出完毕后打印一个回车换行。
void
println()
通过写入行分隔符字符串终止当前行。void
println(boolean x)
打印 boolean 值,然后终止行。void
println(char x)
打印字符,然后终止该行。void
println(char[] x)
打印字符数组,然后终止该行。void
println(double x)
打印 double,然后终止该行。void
println(float x)
打印 float,然后终止该行。void
println(int x)
打印整数,然后终止该行。void
println(long x)
打印 long,然后终止该行。void
println(Object x)
打印 Object,然后终止该行。void
println(String x)
打印 String,然后终止该行。
8.2 PrintWriter
PrintStream的问题是它不支持国际化,不能用与平台无关的方式处理换行。所以在JDK 1.1中引入了PrintWriter类,它是字符流,依旧使用与PrintStream相同的格式化接口print()和println()方法,但提供了国际化支持。在输出方面,PrintWriter比PrintStream更为合适。
构造方法:
PrintWriter(File file)
使用指定文件创建不具有自动行刷新的新 PrintWriter。PrintWriter(File file, String csn)
创建具有指定文件和字符集且不带自动刷行新的新 PrintWriter。PrintWriter(OutputStream out)
根据现有的 OutputStream 创建不带自动行刷新的新 PrintWriter。PrintWriter(String fileName)
创建具有指定文件名称且不带自动行刷新的新 PrintWriter。PrintWriter(String fileName, String csn)
创建具有指定文件名称和字符集且不带自动行刷新的新 PrintWriter。PrintWriter(Writer out)
创建不带自动行刷新的新 PrintWriter。特有方法:
已与PrintStream相同的格式化接口print()和println()方法
void
write(char[] buf)
写入字符数组。void
write(char[] buf, int off, int len)
写入字符数组的某一部分。void
write(int c)
写入单个字符。void
write(String s)
写入字符串。void
write(String s, int off, int len)
写入字符串的某一部分。write方法效果与print方法相同
代码演示:
public static void main(String[] args) throws FileNotFoundException { //创建对象 PrintWriter printWriter = new PrintWriter("8.txt"); //写入数据 printWriter.write("hello"); printWriter.print(" "); printWriter.println("世界"); //关闭打印流 printWriter.close(); System.out.println("写入完毕"); }
9.流的使用
IO流中对象很多,解决问题(处理设备上的数据时)到底该用哪个对象呢?
第一步:明确操作的数据类型,是文本还是其它二进制文件?
文本:Reader、Writer
其它二进制:InputStream、OutputStream
第二步:先明确要操作类型输入还是输出
源:InputStream Reader
目的:OutputStream Writer
第三步:明确是否需要额外的功能
是否需要高效率?
BufferedInputStream
BufferedOuputStream
BufferedWriter
BufferedReader
10.总结
- 字节流
- 字节输入流 InputStream
- FileInputStream 操作文件的字节输入流
- BufferedInputStream高效的字节输入流
- 字节输出流 OutputStream
- FileOutputStream 操作文件的字节输出流
- BufferedOutputStream 高效的字节输出流
- 字符流
- 字符输入流 Reader
- FileReader 操作文件的字符输入流
- BufferedReader 高效的字符输入流
- InputStreamReader 输入操作的转换流(把字节流封装成字符流)
- 字符输出流 Writer
- FileWriter 操作文件的字符输出流
- BufferedWriter 高效的字符输出流
- OutputStreamWriter 输出操作的转换流(把字节流封装成字符流)
- 方法:
- 读数据方法:
- read() 一次读一个字节或字符的方法
- read(byte[] char[]) 一次读一个数组数据的方法
- readLine() 一次读一行字符串的方法(BufferedReader类特有方法)
- readObject() 从流中读取对象(ObjectInputStream特有方法)
- 写数据方法:
- write(int) 一次写一个字节或字符到文件中
- write(byte[] char[]) 一次写一个数组数据到文件中
- write(String) 一次写一个字符串内容到文件中
- writeObject(Object ) 写对象到流中(ObjectOutputStream类特有方法)
- newLine() 写一个换行符号(BufferedWriter类特有方法)