字符流:就是在字节流的基础上,加上编码,形成的数据流
字符流出现的意义:因为字节流在操作字符时,可能会有中文导致的乱码,所以由字节流引申出了字符流。
字符输入流:Reader
常用子类:FileReader
文件字符输入流常用方法:
read();
read(char[ ]);
read(char[ ] ,offset,len);
字符输出流: Writer
常用子类:文件字符输出流: Filewriter
文件字符输出常用方法:
writer();
writer(char[ ]);
writer(char[ ],offset,len);
writer(string);
flush()刷新缓冲区
注意:close()方法默认调用了flush()方法,但是flush()方法只刷新缓冲区,而close()还会关闭IO流
栗子一:读取文件
package dome8; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.Reader; public class ZFL { /* (a=reader.read()) != -1做了三件事 1.执行reader.reda(),取文件中读取一个字符 2.执行ch=reader.read(),将读取到的字符赋值给变量 3.(ch=reader.read())!=-1,用读取到的字符(内容)和-1进行比较 * */ //创建一个文件 文件里面有abc三个字符 //read() 读一个字符,返回该字符相应的ASCII码值,读不到返回-1 public static void main(String[] args) throws IOException { //创建字符流对象 Reader reader = new FileReader("T//1.txt"); //需要抛异常 //以字符流的方式读取文件 // int a = reader.read(); // System.out.println(a); // int b = reader.read(); // System.out.println(b); // int c = reader.read(); // System.out.println(c); // int d = reader.read(); //如果没有则返回-1 // System.out.println(d); //优化上诉的读法,用循环改进 //又因为不知道循环次数,所有用while循环 int a; //定义变量,用来接收读取到的字符 while ((a=reader.read()) != -1){ // a=reader.read(); System.out.println(a); } //关闭资源 reader.close(); } }
栗子二:拷贝文件数组
package dome8; import java.io.*; public class ZFL3 { public static void main(String[] args) throws IOException { //创建目标目录 FileReader reader = new FileReader("T//1.txt"); //创建对象目录 FileWriter writer = new FileWriter("T//2.txt"); char[] b = new char[1024]; int a; while ((a=reader.read(b))!=-1){ writer.write(b,0,a); //写入文件 } //释放资源 reader.close(); writer.close(); } }
字符流与字节流的区别:字符流虽然以字节流为基础创建的,但是字节流可以支持声音,视频,图片,文本等所有文件类型,而字符流只支持文本文件。
带缓冲区的字符流:
BufferedReader/BufferedWriter 带缓冲区的字符输入流与字符输出流。
带缓冲区的字符输入流:BufferedReader:常用方法:readLine() 读取一行,如果为文件末尾,返回值为null。
带缓冲区的字符输出流:BufferedWriter:常用方法:writer(string)将字符串写入 到输出流。 newLine()根据系统的行分割符进行换行。
栗子一:
package dome8; import java.io.*; public class ZFL3 { public static void main(String[] args) throws IOException { //需求:通过字符缓冲流,将1.txt中的内容拷贝到2.txt文件中 //1.创建字符缓冲流对象,关联数据源文件 //1.1创建普通字符流对象 FileReader reader = new FileReader("T//1.txt"); //1.2创建字符缓冲流对象 BufferedReader fb = new BufferedReader(reader); //简化上述代码 //BufferedReader fb = new BufferedReader(new FileReader("T//1.txt") ); //2.创建字符缓冲输出流对象,关联目的地文件 //2.1创建普通的字符输出流对象 FileWriter writer = new FileWriter("T//2.txt"); //2.2创建字符缓冲流对象 BufferedWriter fw = new BufferedWriter(writer); //3.定义变量,记录读取到的数据 int a; //4.循环读取,只要条件满足就一直读,并将读取到的内容赋值给变量 while ((a=fb.read())!=-1){ //5.将获取到的数据写入到目的地文件中 fw.write(a); } //6.释放资源 fb.close(); fw.close(); } }
栗子二:
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class Demo8 { public static void main(String[] args)throws IOException { BufferedWriter bw=new BufferedWriter(new FileWriter("3.txt")); BufferedReader br=new BufferedReader(new FileReader("1.txt")); String value=""; while((value=br.readLine())!=null) { bw.write(value); bw.newLine(); //换行 } bw.close(); br.close(); } }
编码与乱码:
乱码:编码与解码不一致,导致的乱码问题,每一种编码格式都有自己独特的编码,如果编码与解码不一致,势必会导致乱码,例如用Unicode编码,用gbk解码,就会字符与码值不匹配,从而导致乱码。
编码表:编码和解码使用的规则:
ASCII码:美国信息交换标准代码。单字节编码,不支持中文。
gbk:国标码;
Unicode/utf-8 :双字节编码,支持中文(万国码)
代码示例:
public class 读取不同编码的文本文件 { public static void main(String[] args) throws IOException { // BufferedReader br=new BufferedReader(new FileReader(new File("C:\Users\Administrator\De sktop\6.txt"))); // 改进 BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream(new File("C: Users\Administrator\Desktop\6.txt")),"gbk")); String st = br.readLine(); System.out.println(st); } }
转换流
1.InputStreamReader 将字节流转换成字符流 输入
2.OutputStreamWriter 将字节流转换成字符流 输出
3. 构造方法:
① InputStreamReader(InputStream in)
② InputStreamReader(InputStream in, String cs)
③ OutputStreamWriter(OutputStream out)
④ OutputStreamWriter(OutputStream out, String charsetName)
4. 作用:
① 可以将字节流转换成字符流
② 可以使用指定的编码来读取或写入流。
代码示例:
1 public class 转换流 { 2 public static void main(String[] args) throws IOException { 3 InputStreamReader is=new InputStreamReader(new FileInputStream(new File("C:\Users\Administ 4 rator\Desktop\6.txt")),"gbk"); 5 char[] c=new char[1024]; 6 int value = is.read(c); 7 System.out.println(Arrays.toString(c)); 8 } 9 }
字节数组字节输出流
ByteArrayOutputStream
字节数组字节输出流:
特点: 可以将数据写入到 byte 数组中,并且该缓冲区可以随着写入的数据而自增
① 构造方法 :
ByteArrayOutputStream()
② 注意:此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException
③ 常用方法:
1 》 write(byte[]) 将 byte[] 中的值写入缓冲区字节数组,该缓冲区随着数据的增多而自增。
2 》 toString() 要想获取缓冲区的字节数据,可以通过该方法将其转换为字符串。
代码示例:
1 public class 字节数组字节输出流 { 2 public static void main(String[] args) throws IOException { 3 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 4 String s="abc"; 5 byte[] b=s.getBytes(); 6 System.out.println(Arrays.toString(b)); 7 bos.write(b); 8 bos.write(b); 9 bos.close(); 10 System.out.println(Arrays.toString(b)); 11 System.out.println(bos.toString()); 12 } 13 }
对象流 / 序列化与反序列化流
1. 对象流 / 序列化流
ObjectInputStream: 反序列化流
② ObjectOutputStream: 序列化流
1 》常用方法:
writeObject(obj) 将 obj 对象写入到流中
readObject 读取流中的数据
① EOFException 表示读取流意外读到了文件的末尾 ( 就是一个空文件。 )
2 》构造方法
ObjectOutputStream(OutputStream out)
ObjectInputStream(InputStream in)
3 》序列化版本号:
serialVersionUID 序列化版本号:保证序列化流与反序列化流读写一致,保证版本一致性。
栗子一:
public class 用序列化流与反序列化流操作集合 { public static void main(String[] args) { ArrayList<Teacher> list=new ArrayList<>(); list.add(new Teacher(" 张三 ", 18, new ClassRoom("0318java"))); list.add(new Teacher(" 李四 ", 18, new ClassRoom("0318java"))); list.add(new Teacher(" 王五 ", 18, new ClassRoom("0318java"))); // writeToFile(list,"stu.txt"); // 读取 System.out.println(readTeacher("stu.txt")); } // 带异常处理的 ,序列化 public static void writeToFile(ArrayList<Teacher> list,String fileName) { // 序列化流进行写入 try( ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(new File(fileName))); ){ oos.writeObject(list); }catch (Exception e) { e.printStackTrace(); } } // 反序列化 public static ArrayList<Teacher> readTeacher(String fileName) { ArrayList<Teacher> list=null; // 反序列化流读取文件中的集合 try( ObjectInputStream ois=new ObjectInputStream(new FileInputStream(new File(fileName))); ){ list = (ArrayList<Teacher>) ois.readObject(); }catch (Exception e) { e.printStackTrace(); } return list; } } class Teacher implements Serializable{ /** * 序列化版本号:默认版本号为 1l */ private static final long serialVersionUID = 1L; private String name; private int age; private ClassRoom cn;// 班级 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; } public ClassRoom getCn() { return cn; } public void setCn(ClassRoom cn) { this.cn = cn; } @Override public String toString() { return "Teacher [name=" + name + ", age=" + age + ", cn=" + cn + "]"; } public Teacher() { super(); // TODO Auto-generated constructor stub } public Teacher(String name, int age) { super(); this.name = name; this.age = age; } } public Teacher(String name, int age, ClassRoom cn) { super(); this.name = name; this.age = age; this.cn = cn; } } class ClassRoom implements Serializable{ /** * 序列化版本号:保证序列化流与反序列化流读写一致 */ private static final long serialVersionUID = 3359646767342429683L; private String no; public ClassRoom() { super(); // TODO Auto-generated constructor stub } public ClassRoom(String no) { super(); this.no = no; } @Override public String toString() { return "ClassRoom [no=" + no + "]"; } public String getNo() { return no; } public void setNo(String no) { this.no = no; }// 班级号码 }
栗子二:
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.ArrayList; import java.util.Iterator; public class Demo9 { public static void main(String[] args)throws IOException, Exception { ArrayList<Student6> list=new ArrayList<>(); list.add(new Student6("张三","1001",18)); list.add(new Student6("李四","1002",19)); list.add(new Student6("王五","1003",20)); ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(new File("4.txt"))); oos.writeObject(list); oos.close(); ObjectInputStream ois=new ObjectInputStream(new FileInputStream(new File("4.txt") )); ArrayList<Student6> list2=(ArrayList<Student6>) ois.readObject(); Iterator<Student6> it=list2.iterator(); while(it.hasNext()) { Student6 stu=it.next(); System.out.println("姓名:"+stu.getName()+" 学号:"+stu.getStuNo()+" 年龄+ :"+stu.getAge()); } } } class Student6 implements Serializable{ /** * */ private static final long serialVersionUID = 2658878058482366562L; private String name; private String stuNo; private int age; public Student6() { super(); } public Student6(String name,String stuNo,int age) { this.name=name; this.stuNo=stuNo; this.age=age; } public void setName(String name) { this.name=name; } public String getName() { return name; } public void setStuNo(String stuNo) { this.stuNo=stuNo; } public String getStuNo() { return stuNo; } public void setAge(int age) { this.age=age; } public int getAge() { return age; } @Override public String toString() { return "Student6 [name=" + name + ", stuNo=" + stuNo + ", age=" + age + "]"; } }
EOFException表示输入过程中意外地到达文件尾或流尾的信号
字符流写入 要刷新/关流才能写入(刷新也是调用了flush(刷新)方法)
就像水龙头带软管,开水龙头要等一会儿水才能流出来,就和需要刷新一样
字节流不需要刷新,是因为字节流是一个字节一个字节读和写的,而字符流是三个字节或者两个字节读和写的,所以
字符流需要刷新,而字节流不需要刷新