第五章 IO 输入流 & 输出流
IO InputStream,OutputStream 输入流与输出流
流的方向不同,操作不同,输入流用来读取数据,输出流用来写入数据
而所有的字节输入流都继承自InputStream,
所有的输出流都继承自OutputStream;
流有两个分类:
节点流:实际连接程序与数据之间的“管道”;负责搬运数据的流,特点是数据源明确
处理流:不能独立存在,一定是连接在其他流上,目的是数据流经该流时可以对其做加工处理,简化我们对数据的操作
一、文件流:
java.io.FileInputStream,FileOutputStream
它们是一对低级流,是用来读写文件的流
与RandomAccessFile功能一样,但是底层实际的读写方式是不同的,RAF是基于指针的随机读写形式,所以可以更灵活的编辑文件
文件流是基于java标准的IO读写,所以是顺序读写形式
对于文件而言,不能修改文件的部分内容,但是依靠流的特性,可以时用流连接完成一些复杂操作
main:
//FileOutputStream fos =new FileOutputStream("fos.txt");//如果文件存在,此方法会覆盖文件内容
FileOutputStream fos =new FileOutputStream("fos.txt",true);//内容追加
* 文件输出流有两种创建模式:
* 覆盖写模式:FileOutputStream(String str);
* FileOutputStream(File file);
* 创建流时若指定文件已存在,则会将该文件数据清除,
然后通过该流写出的内容作为文件新数据
*FileOutputStream fos =new FileOutputStream("fos.txt");//
* 追加写模式:FileOutputStream(String str,boolean append);
* FileOutputStream(File file ,boolean append);
* 若传入第二个参数,并且值为true时则是追加写模式
* 即写出的数据会被追加在文件末尾
String str ="像一颗海草海草海草,随波飘摇~";
byte[]data=str.getBytes("UTF-8");
fos.write(data);
System.out.println("写出完毕!");
fos.close();
【案例】使用文件流复制文件
1 public class CopyDemo { 2 public static void main(String[]args) throws IOException { 3 FileInputStream fis=new FileInputStream("fos.txt"); 4 FileOutputStream fos=new FileOutputStream("fos_1.txt"); 5 byte[]data=new byte[10]; 6 int len=-1; 7 while((len=fis.read(data))!=-1) { 8 System.out.println(len); 9 fos.write(data,0,len); 10 } 11 System.out.println("读写完毕"); 12 fis.close(); 13 fos.close(); 14 } 15 } 16 17
二、缓冲流:提高读写效率
java.io.BufferedInputStream
java.io.BufferedOutputStream
缓冲流是一种高级流,作用是提高读写效率,在流连接中只要连接了这组流,无论我们的读写是以单字节读写,还是以块读写,最终流经缓冲流时都会改变为块读写,提高读写效率
main:
1 FileInputStream fis=new FileInputStream("fos.txt"); 2 BufferedInputStream bis=new BufferedInputStream(fis); 3 4 FileOutputStream fos= new FileOutputStream("fos_2.txt"); 5 BufferedOutputStream bos=new BufferedOutputStream(fos); 6 7 //byte[]data=new byte[10]; 8 int d=-1; 9 while((d=bis.read())!=-1) { 10 System.out.println(d); 11 bos.write(d); 12 } 13 System.out.println("复制完毕!"); 14 /* 15 * 关闭流时先关高级流 16 */ 17 bis.close(); 18 bos.close(); 19 20 缓冲区: 21 main: 22 FileOutputStream fos=new FileOutputStream("bos.txt"); 23 BufferedOutputStream bos=new BufferedOutputStream(fos); 24 String str="夜空中最亮的星"; 25 byte[]data=str.getBytes("UTF-8"); 26 fos.write(data); 27 System.out.println("写出完毕"); 28 29 // bos.flush();//强制缓存区数据一次性写出,可保证即时性 30 (写的次数增多,可能会拉低总体写效率) 31 bos.close();//关闭高级流时会先调用bos.flush,
三、对象流:
java.io.ObjectOutputStream;
java.io.ObjectInputStream;
它们是一对高级流,可以方便的读写java中的任何对象
写:
main:
Person p = new Person(); p.setName("刘老师"); p.setGender("man"); p.setAge(18); String[]otherInfo= {"是一名老师","爱好是写毛笔字","促进学习交流","是我们的老师"}; p.setOtherInfo(otherInfo); System.out.println(p); * 将p对象写入文件 FileOutputStream fos=new FileOutputStream("Object.obj"); ObjectOutputStream oos=new ObjectOutputStream(fos); oos.writeObject(p); System.out.println("输出完毕!"); oos.close();
* 对象输出流提供类一个独有的方法:writeObject()
* 该方法可以将给定的对象转换为一组字节,然后将该组字节通过其连接的流写出
* 这里连接的是文件输出流,所以将转换的这组字节写入了文件
*这里经历了两个步骤:
*1:oos会将给定的对象转换为一组字节(这个过程称为:对象序列化)
*2:fos会将这组字节写入到文件中(这个过程称为:数据持久化)
//NotSerializableException
* 一个类的实例若希望被对象流进行读写,
* 那么该类必须实现接口:java.io.Serializable
class Person implements Serializable{}
* 该接口不需要重写方法,称之为签名接口,目的是提示编译器在编译后的class文件中添加一定的方法,使得对象流写入时有方法可识别调用
* 当一个类实现了Serializable接口后,应当添加一个常量:serialVersionID 序列化版本号
* 序列化版本号直接影响一个对象是否能够被反序列化
* 当OIS进行反序列化对象时,会比对该对象与当前类的版本号是否一致,若不一致则反序列化会抛出异常,否则进行父那序列化操作
* 若我们的类没有主动添加版本号,那么编译器在编译当前类时会根据当前类的结构生成一个版本号,
* 只要当前类结构没有改变,版本号就时固定的,改变了则版本号也会改变
* 自定义版本号 ,可以在当前类发生了改变时通过控制版本号来决定原来的对象是否能反序列化,所以都建议自行添加版本号
*
* 当一个属性被transient修饰后,那么当该类实例被序列化时,这个属性值会被忽略,忽略可有可无的属性可以达到对象序列化瘦身的目的
读:对象反序列化
main:
FileInputStream fis =new FileInputStream("Person.obj"); ObjectInputStream ois = new ObjectInputStream(fis); Person p=(Person)ois.readObject(); System.out.println(p); ois.close();
---------------------------------------------------------------------------------------------------------
第六章 字符流
* java将流按照读写单位划分为:字节流,字符流
*
* 字符流是以字符为单位进行读写的流,所以字符流天生具有编解码能力,也因此字符流读写的只能是【文本数据】
* 但是底层实际还是读写字节,只是字节与字符的转换工作字符流会自行完成
*
* java.io.Reader:字符输入流的超类,定义了所有字符输入流都应当具备的读取字符的相关方法
* java.io.Writer:字符输出流的超类
*
* 转换流:
* java.io.InputStreamReader;
* java.io.OutputStreamWriter;
* 它们是一对高级流,是字符流的一对常用实现类,在实际操作字符流时,它们是流连接中的一环;
* 由于具有更多高级功能的其他字符的高级流都只能连接在其他字符流上,而大部分的低级流都是字节流,
* 而转换流是唯一可以连接字节流的字符流,那么在流连接中可以起到称上启下的作用
【案例】使用字符流读取字符
1 public class InputStreamReader_read { 2 public static void main(String[] args) throws IOException { 3 FileInputStream fis = new FileInputStream("osw.txt"); 4 InputStreamReader isr = new InputStreamReader(fis,"utf-8"); 5 //读一个字符 6 //char c = (char)isr.read(); 7 //System.out.println(c); 8 9 //读所有字符(循环) 10 int d=-1; 11 while((d=isr.read())!=-1) { 12 char c =(char)d; 13 System.out.print(c); 14 } 15 } 16 }
【案例】使用字符流写入字符
public class OutputStreamWriter_write { public static void main(String[] args) throws IOException { FileOutputStream fos = new FileOutputStream("osw.txt"); OutputStreamWriter osw = new OutputStreamWriter(fos,"UTF-8"); osw.write("磨擦磨擦,似魔鬼的步伐;"); osw.write("在光滑的马路牙子上打出溜儿滑。"); System.out.println("写出完毕"); osw.close(); } }
【案例】缓冲字符输入流(按行读取字符串)
1 public class BufferedReader_readLine { 2 public static void main(String[] args) throws IOException { 3 /* 4 * 将当前代码输出到控制台 5 */ 6 FileInputStream fis = new FileInputStream("./src/io/BufferedReader_readLine.java");//文件输入流,将文件以字节形式输入 7 InputStreamReader isw = new InputStreamReader(fis);//字符转换输入流,将字节转换为字符串 8 BufferedReader br = new BufferedReader (isw);//字符缓冲输入流,按行读取字符串 9 // String str = br.readLine();//写一行 10 // System.out.println(str); 11 /* 12 * str.readLine() String型 13 * 读取一行字符串 14 * 连续读取若干字符,直接读取了换行符,然后将换行符之间所有的字符以一个字符串形式返回 15 * 返回的字符串中不包含最后的换行符 16 * 若返回值为null时,表示读取到了末尾 17 */ 18 String str =null; 19 while((str=br.readLine())!=null) { 20 System.out.println(str); 21 } 22 br.close(); 23 } 24 }
【案例】缓冲字符输出流(写入字符串)
public class BufferedOutputStream_flush { public static void main(String[] args) throws IOException { FileOutputStream fos=new FileOutputStream("bos.txt"); BufferedOutputStream bos=new BufferedOutputStream(fos); String str="夜空中最亮的星"; byte[]data=str.getBytes("UTF-8"); fos.write(data); System.out.println("写出完毕"); // bos.flush();//强制缓存区数据一次性写出,可保证即时性(写的次数增多,可能会拉低总体写效率) bos.close();//关闭高级流时会先调用bos.flush, } }
【案例】复制
/** * 使用缓冲流提高读写效率 * java.io.BufferedInputStream * java.io.BufferedOutputStream * 缓冲流是一种高级流,作用是提高读写效率,在流连接中只要连接了这组流,无论我们的读写是以单字节读写,还是块读写 * 最终流经缓冲流时都会改变为块读写形式,提高读写效率 */ public class CopyDemo2 { public static void main(String[] args) throws IOException { FileInputStream fis=new FileInputStream("fos.txt"); BufferedInputStream bis=new BufferedInputStream(fis); FileOutputStream fos= new FileOutputStream("fos_2.txt"); BufferedOutputStream bos=new BufferedOutputStream(fos); // byte[]data=new byte[10]; int d=-1; while((d=bis.read())!=-1) { System.out.println(d); bos.write(d); } System.out.println("复制完毕!"); /* * 关闭流时先关高级流 */ bis.close(); bos.close(); } }