转换流
InputStreamReader/OutputStreamWriter用来实现将字节流转化 成字符流。
通过转换流解决乱码
ANSI(American National Standards Institute)美国国家标准协会
public class TestInputStreamReader { public static void main(String[] args) { //创建文件字节输入流对象 try(FileInputStream fis = new FileInputStream("d:/sxt.txt"); //创建转换流(字节到字符的转换)流对象,并在该对象中指定编码。 InputStreamReader isr = new InputStreamReader(fis,"gbk")){ StringBuilder sb = new StringBuilder(); //操作流对象 int temp = 0; while((temp = isr.read()) != -1) { sb.append((char) temp); } System.out.println(sb); }catch(IOException e){ e.printStackTrace(); } } }
通过转换流实现键盘输入屏幕输出
import java.io.*; public class TestConvertStream { public static void main(String[] args) { // 创建字符输入和输出流:使用转换流将字节流转换成字符流 BufferedReader br = null; BufferedWriter bw = null; try { br = new BufferedReader(new InputStreamReader(System.in)); bw = new BufferedWriter(new OutputStreamWriter(System.out)); // 使用字符输入和输出流 String str = br.readLine(); // 一直读取,直到用户输入了exit为止 while (!"exit".equals(str)) { // 写到控制台 bw.write(str); bw.newLine();// 写一行后换行 bw.flush();// 手动刷新 // 再读一行 str = br.readLine(); } } catch (IOException e) { e.printStackTrace(); } finally { // 关闭字符输入和输出流 if (br != null) { try { br.close(); } catch (IOException e) { e.printStackTrace(); } } if (bw != null) { try { bw.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
通过字节流读取文本文件并添加行号
public class TestLineNumber2 { public static void main(String[] args) { //创建字符输入缓冲流、输入字节到字符转换流、文件字节输入流对象 try(BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("d:/sxt.txt"))); //创建字符输出缓冲流、输出字符到字节转换流、文件字节输出流对象 BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("d:/sxt4.txt")))){ //操作流 String temp = ""; //序号变量 int i = 1; //按照行读取 while((temp = br.readLine()) != null){ bw.write(i+","+temp); //换行 bw.newLine(); //序号累加 i++; } //刷新 bw.flush(); }catch(IOException e){ e.printStackTrace(); } } }
通过转换流实现键盘输入屏幕输出
System.in是字节流对象,代表键盘的输入。
System.out是字节流对象,代表输出到屏幕。
public class TestKeyboardInput { public static void main(String[] args) { //创建键盘输入相关流对象 try(BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); //创建向屏幕输出相关流对象 BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out))){ while(true){ bw.write("请输入:"); bw.flush(); //获取键盘输入的字符串 String input = br.readLine(); //判断输入的内容是否含有退出关键字。 if("exit".equals(input) || "quit".equals(input)){ bw.write("Bye Bye !"); bw.flush(); break; } //将读取到键盘输入的字符串,输出到屏幕。 bw.write("您输入的是:"+input); bw.newLine(); bw.flush(); } }catch(IOException e){ e.printStackTrace(); } } }
字符输出流
在Java的IO流中专门提供了用于字符输出的流对象PrintWriter。该 对象具有自动行刷新缓冲字符输出流,特点是可以按行写出字符 串,并且可通过println();方法实现自动换行。
public class TestPrintWriter { public static void main(String[] args) { //创建字符输出流对象 try(PrintWriter pw = new PrintWriter("d:/sxt5.txt")){ //调用不带换行方法完成内容的输出 pw.print("abc"); pw.print("def"); //调用带有自动换行方法完成内容的输出 pw.println("Oldlu"); pw.println("sxt"); pw.flush(); }catch(IOException e){ e.printStackTrace(); } } }
通过字符输出流添加行号
public class TestLineNumber3 { public static void main(String[] args) { //创建字符输入缓冲流对象与文件字符输入流对象 try(BufferedReader br = new BufferedReader(new FileReader("d:/sxt.txt")); //创建字符输出流对象 PrintWriter pw = new PrintWriter("d:/sxt6.txt")){ //操作流 String temp = ""; //定义序号变量 int i = 1; while((temp = br.readLine()) != null){ pw.println(i+","+temp); //序号累加 i++; } //刷新 pw.flush(); }catch(IOException e){ e.printStackTrace(); } } }
数据流
数据流将“基本数据类型与字符串类型”作为数据源,从而允许程序 以与机器无关的方式从底层输入输出流中操作Java基本数据类型与 字符串类型。 DataInputStream和DataOutputStream提供了可以存取与机器无 关的所有Java基础类型数据(如:int、double、String等)的方 法。
public class TestDataStream { public static void main(String[] args) { //创建数据输出流对象与文件字节输出流对象 try(DataOutputStream dos = new DataOutputStream(new FileOutputStream("d:/data")); //创建数据输入流对象与文件字节输入流对象 DataInputStream dis = new DataInputStream(new FileInputStream("d:/data"))){ //将如下数据写入到文件中 dos.writeChar('a'); dos.writeInt(10); dos.writeDouble(Math.random()); dos.writeBoolean(true); dos.writeUTF("山东聊城"); //手动刷新缓冲区:将流中数据写入到文件中 dos.flush(); //直接读取数据:读取的顺序要与写入的顺序一致,否则不能正确读取数据。 System.out.println("char: " + dis.readChar()); System.out.println("int: " + dis.readInt()); System.out.println("double: " + dis.readDouble()); System.out.println("boolean: " + dis.readBoolean()); System.out.println("String: " + dis.readUTF()); }catch(IOException e){ e.printStackTrace(); } } }
Oldlu提示: 使用数据流时,读取的顺序一定要与写入的顺序一致,否则不 能正确读取数据。
对象流
我们前边学到的数据流只能实现对基本数据类型和字符串类型的读 写,并不能读取对象(字符串除外),如果要对某个对象进行读写 操作,我们需要学习一对新的处理流:
ObjectInputStream/ObjectOutputStream。
处理基本数据类型数据
ObjectInputStream/ObjectOutputStream处理基本数据类型。
public class TestObjectStreamBasicType { public static void main(String[] args) { //创建对象输出流对象与文件字节输出流对象 try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("d:/data2")); //创建对象输入流对象与文件字节输入流对象 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/data2"))){ //将如下数据写入到文件中 oos.writeInt(10); oos.writeDouble(Math.random()); oos.writeChar('a'); oos.writeBoolean(true); oos.writeUTF("你好,山东聊城"); oos.flush(); //必须要按照写入的顺序读取数据 System.out.println("int: "+ois.readInt()); System.out.println("double: "+ois.readDouble()); System.out.println("char: "+ois.readChar()); System.out.println("boolean: "+ois.readBoolean()); System.out.println("String: "+ois.readUTF()); }catch(IOException e){ e.printStackTrace(); } } }
注意
1、对象流不仅可以读写对象,还可以读写基本数据类型。
2、读写基本数据类型时,读取的顺序一定要与写入的顺序一致,否则不能正确读取数据。
复习:
IO流技术介绍
什么是IO
输入(Input)指的是:可以让程序从外部系统获得数据(核心含义是 “读”,读取外部数据)。 输出(Output)指的是:程序输出数据给外部系统从而可以操作外部 系统(核心含义是“写”,将数据写出到外部系统)。 java.io包为我们提供了相关的API,实现了对所有外部系统的输入输 出操作,这就是我们这章所要学习的技术。
什么是数据源
数据源data source,提供数据的原始媒介。常见的数据源有:数据 库、文件、其他程序、内存、网络连接、IO设备。如图所示。
数据源分为:源设备、目标设备。
1 源设备:为程序提供数据,一般对应输入流。
2 目标设备:程序数据的目的地,一般对应输出流。
流的概念
流是一个抽象、动态的概念,是一连串连续动态的数据集合。 对于输入流而言,数据源就像水箱,流(stream)就像水管中流动着 的水流,程序就是我们最终的用户。我们通过流(A Stream)将数 据源(Source)中的数据(information)输送到程序 (Program)中。 对于输出流而言,目标数据源就是目的地(dest),我们通过流(A Stream)将程序(Program)中的数据(information)输送到目 的数据源(dest)中。
流与源数据源和目标数据源之间的关系:
Oldlu提示
输入/输出流的划分是相对程序而言的,并不是相对数据源。
第一个简单的IO流程序
当程序需要读取数据源的数据时,就会通过IO流对象开启一个通向 数据源的流,通过这个IO流对象的相关方法可以顺序读取数据源中 的数据。
使用流读取文件内容(不规范的写法,仅用于测试)
import java.io.*; public class TestI01 { public static void main(String[] args) { try { //创建输入流 FileInputStream fis = new FileInputStream("d:/a.txt"); // 文件内容是:abc //一个字节一个字节的读取数据 int s1 = fis.read(); // 打印输入字符a对应的ascii码值97 int s2 = fis.read(); // 打印输入字符b对应的ascii码值98 int s3 = fis.read(); // 打印输入字符c 对应的ascii码值99 int s4 = fis.read(); // 由于文件内容已经读取完毕,返回-1 System.out.println(s1); System.out.println(s2); System.out.println(s3); System.out.println(s4); // 流对象使用完,必须关闭!不然,总占用系统资源,最终会造成系统崩溃! fis.close(); } catch (Exception e) { e.printStackTrace(); } } }
以上案例我们要注意以下几点:
1、我们读取的文件内容是已知的,因此可以使用固定次数的“int s= fis.read();”语句读取内容,但是在 实际开发中通常我们根本不知道文件的内容,因此我们在读取的时候需要配合while循环使用。
2、 为了保证出现异常后流的正常关闭,通常要将流的关闭语句要放到finally语句块中,并且要判断流 是不是null。
IO流的经典写法
使用流读取文件内容(经典代码,一定要掌握)
import java.io.*; public class Test2 { public static void main(String[] args) { FileInputStream fis = null; try { fis = new FileInputStream("d:/a.txt"); // 内容是:abc StringBuilder sb = new StringBuilder(); int temp = 0; //当temp等于-1时,表示已经到了文件结尾,停止读取 while ((temp = fis.read()) !=-1) { sb.append((char) temp); } System.out.println(sb); } catch (Exception e) { e.printStackTrace(); } finally { try { //这种写法,保证了即使遇到异常情况,也会关闭流对象。 if (fis != null) { fis.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
IO流新语法经典写法
在JDK7以及以后的版本中可以使用try-with-resource语法更优雅的 关闭资源。
java.lang.AutoCloseable接口: 在java.lang.AutoCloseable接口中包含了一个close方法,该方法用 于关闭资源。 只要是实现了java.lang.AutoCloseable接口的对象,都可以使用 try-with-resource关闭资源。 使用最新的try-with-resource简化(经典代码,一定要掌握)
public class Test3 { public static void main(String[] args) { //使用try-with-resource方式关闭资源。 //在try中打开资源,不需要在代码中添加finally块关闭资源。 try(FileInputStream fis = new FileInputStream("d:/a.txt");){ StringBuilder sb = new StringBuilder(); int temp=0; while((temp = fis.read()) != -1) { sb.append((char) temp); } System.out.println(sb); }catch(Exception e){ e.printStackTrace(); } }
Oldlu建议 如上代码是一段非常典型的IO流代码,其他流对象的使用也 基本是同样的模式!