黑马程序员—Java中的IO流
2015-07-08 14:34
621 查看
11. IO流
11.1IO流概述
IO流用来处理设备之间的数据传输。流按操作数据分为两种:字节流与字符流。
流按流向分为:输入流,输出流。
字节流的抽象基类:InputStream OutputSream
字符流的抽象基类:Reader Writer
11.2字符流
1)FileWriter
IO异常处理方式:
对已有文件的数据续写:
2)FileReader
3)拷贝文本文件
11.3字符流的缓冲区
缓冲区的出现提高了对数据的读写效率,缓冲区要结合流才可以使用,在创建缓冲区之前,必须要先有流对象
1) BufferedWriter
该缓冲区中提供了一个跨平台的换行符:newLine();
2) BufferedReader
该缓冲区提供了一个一次读一行的方法,方便于对文本数据的获取:readLine()。当返回null时表示读到文件末尾,返回的时候只返回回车符之前的数据内容。
LineNumberReader类:是BufferedReader类的子类,有两个新方法
getLineNumber():获得当前行号
setLineNumber():设置当前行号
11.4装饰设计模式
当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能,并提供加强功能,那么自定义的该类称为装饰类
装饰类通常会通过构造方法接收被装饰的对象,并基于被装饰的对象的功能,提供更强的功能。
装饰模式比继承更灵活,避免了继承体系的臃肿,而且降低了类与类之间的关系。装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强的功能,所以装饰类和被装饰类通常都属于一个体系中。
装饰类和被装饰类都是,被装饰类父类的一个子类。创建自定义装饰类时,要继承父类,那么需要复写父类中的抽象方法
11.5字节流
1) FileInputSream (读)
2) FileOutputSream (写)
11.6字节流的缓冲区
BufferedOutputStream
BufferedInputStream
11.7读取键盘录入
System.in:对应的标准输入设备:键盘
1) InputStreamReader
是字节流通向字符流的桥梁,将字节流对象转成字符流对象。
2) OutputStreamWriter
字符流通向字节流的桥梁。
11.8流操作规律
1) 明确源和目的
源:输入流。InputStream Readerr
目的:输出流 OutputStream Writer
2) 操作的数据是否是纯文本
是:字符流
不是:字节流
3) 当体系明确后,再明确要使用哪个具体的对象
通过设备来进行区分
源设备:内存ArrayStream,硬盘 FileStream,键盘 System.in
目的设备:内存 ArrayStream,硬盘 FileStream,控制台 System.out
改变标准输入输出设备:
//将输入设备由键盘改成PersonDemo.java文件,需要建立一个字节流对象FileInputStream
System.setIn(new FileInputStream(“PersonDemo.java”))
//将输出设备由控制台改成zz.txt文件,需要建立一个字节输出流子类对象PrintStream
System.setOut(new PrintStream(“zz.txt”))
11.9File类
用来将文件或者文件夹封装成对象,方便对文件与文件夹的属性信息进行操作
File类常见方法:
1) 创建
boolean mkdir():创建文件夹,只能创建一级目录
boolean mkdirs():创建多级目录,包括所有必需但不存在的父目录
boolean createNewFile():在指定位置创建文件,如果该文件已经存在,则不创建,返回false。和输出流不一样,输出流对象一建立就会创建文件,而
且文件已经存在,会覆盖。File类要调用方法才创建文件。
2) 删除
boolean delete():如果此句前出现异常将不会执行到,文件就无法删除
void deleteOnExit():在程序退出时删除。在程序运行出现异常的时候也能删除文件。
3) 判断
boolean canExecute():判断文件是否可执行
boolean exists():判断文件是否存在
boolean isDirectory(): 判断文件对象是否是文件或者目录时,必须要先判断
boolean isFile(): 该文件对象封装的内容是否存在,通过exists判断
boolean isHidden():判断文件是否隐藏
4) 获取信息
getName()
getPath()
getParent() 该方法返回的是绝对路径中的父目录,如果File对象封装的是相对路径,返回null。如果相对路径中有上一层目录那么该目录就是返回结果
getAbsolutePath() 获取绝对路径
long lastModified() 获取文件最后被修改的时间
long length()
boolean renameTo() f1.renameTo(f2),变更文件名,还会将文件剪切到指定目录下
File[] listRoots() 列出可用的系统盘符
String[] list() 列出目录下的文件和子目录。调用list方法的file对象必须是封装了一个目录,该目录还必须存在
File[] listFiles() 列出目录下的文件,返回的是File对象的数组
函数自身调用自身,这种表现形式称为递归。使用时需要注意:
1)限定条件
2)要注意递归的次数,尽量避免内存溢出
11.10Properties类
Properties是hashtable的子类,具备map集合的特点,它里面存储的键值对都是字符串。是集合中和IO技术相结合的集合容器。该对象的特点:可以用于键值对形式的配置文件。
Properties中的方法:
setProperty(String key, String value) 向集合中存入键值对
String getProperty(String key) 获取对应键的值
Set<String> stringPropertyNames() 获取Properties对象中键的集合
list(PrintStream out)
list(PrintWriter out)
load(InputStream inStream)
load(Reader reader)
store(OutputStream out, String comments) 将Properties中的键值对存储到配置文件中
store(Writer writer, String comments) 并且加入注释信息comments。
11.11打印流
为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。该流提供了打印方法,可以将各种数据类型的数据都原样打印
字节打印流:
PrintStream
构造函数可以接收的参数类型:
1. file对象 File
2. 字符串路径 String
3. 字节输出流 OutputStream
字符打印流:
PrintWriter
构造函数可以接收的参数类型:
1. file对象 File
2. 字符串路径 String
3. 字节输出流 OutputStream
4. 字符输出流 Writer
PrintWriter(OutputStream out, booleanautoFlush) autoFlush为true时,println方法会
PrintWriter(Writer out, boolean autoFlush) 自动刷新缓存
11.12 序列流SequenceInputStream
11.13对象的序列化
ObjectInputStream ObjectOutputStream
将堆内存中的对象存入的文件当中,对象内的变量数据也被保存;读取文件的可以读取到所存储的对象,直接调用之前的数据。实现了Serializable接口的对象才能被序列化。
在需要序列化的对象中添加static final long serialVersionUID = 42L语句,即使本地的该对象有所修改,也可以读取被序列化的对象,否则会报出InvalidClassException异常。
static 修饰的变量不能被序列化,因为static修饰的内容存在于方法区;transient修饰的变量也不能被序列化,即使变量存在于堆内存中。
11.14管道流
PipedInputStream PipedOutputStream
管道输入流和管道输出流通过不同线程运行。管道流是多线程和IO流的结合应用
11.15RandomAccessFile
该类不是IO体系中的子类,而是直接继承自Object。但是它是IO包中的成员,因为它具备读和写功能,内部封装了一个数组,而且通过指针对数组中的元素进行操作。可以通过getFilePointer获取指针位置,同时可以通过seek改变指针的位置。
能够完成读写的原理就是内部封装了字节输入流和输出流。该类只能操作文件,操作模式通常有只读r和读写rw。
如果模式为只读r,不会创建文件,会去读取一个已存在的文件,如果该文件不存在,则会出现异常。
如果模式为rw,操作的文件不存在,会自动创建;如果存在,则不会覆盖。
该类可以通过多个线程同时对一个文件进行读写操作,下载就是利用此原理
11.16DataStream
可以用于操作基本数据类型的数据的流对象
11.17ByteArrayStream
ByteArrayInputStream : 在构造的时候,需要接收数据源,而且数据源是一个字节数组
ByteArrayOutputStream : 在构造的时候,不用定义数据目的,因为该对象中已经内部封
装了可变长度的字节数组,这就是数据目的地
因为这两个流对象都操作的数组,并没有使用系统资源,所以不用进行close关闭
ByteArrayStream是用流的思想来操作数组
11.1IO流概述
IO流用来处理设备之间的数据传输。流按操作数据分为两种:字节流与字符流。
流按流向分为:输入流,输出流。
字节流的抽象基类:InputStream OutputSream
字符流的抽象基类:Reader Writer
11.2字符流
1)FileWriter
import java.io.*; class FilerWriterDemo { public static void main(String[] args) throws IOException { /*创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件 而且该文件会被创建到指定目录下,如果该目录下已有同名文件,将被覆盖。 其实该步就是在明确数据要存放的目的地*/ FileWriter fw = new FileWriter("demo.txt"); //调用write方法,将字符串写入到流中 fw.write("abcde"); //刷新流对象中的缓冲中的数据,将数据刷到目的地中 fw.flush(); /*关闭流资源,但是关闭之前会刷新一次内部的缓冲中的数据,将数据刷到目的地 和flush区别:flush刷新后,流可以继续使用。close刷新后,会将流关闭。*/ fw.close(); } }
IO异常处理方式:
import java.io.*; class FilerWriterDemo2 { public static void main(String[] args) { FileWriter fw = null; try { //在此处进行fw初始化,以免出现异常时,finally语句无法读取到fw对象 fw = new FileWriter("demo.txt"); fw.write("abcdefg"); } catch (IOException e) { System.out.println(e.toString()); } finally { try { /*当上述语句出现异常时,fw不会创建,fw.close()语句将会出现fw类 文件不存在的异常,因此进行一次判定来解决*/ if(fw!=null) fw.close(); } catch (IOException e) { System.out.println(e.toString()); } } } }
对已有文件的数据续写:
import java.io.*; class FilerWriterDemo3 { public static void main(String[] args) { FileWriter fw = null; try { /*传递一个true参数,代表不覆盖已有的文件, 并在已有文件的末尾处进行数据的续写*/ fw = new FileWriter("demo.txt",true); fw.write("\r\nhaha"); } catch (IOException e) { System.out.println(e.toString()); } finally { try { if(fw!=null) fw.close(); } catch (IOException e) { System.out.println(e.toString()); } } } }
2)FileReader
import java.io.*; class FileReaderDemo { public static void main(String[] args) { /*创建一个文件读取流对象,和指定名称的文件相关联要保证该文件 是已经存在的,如果不存在会发生异常FileNotFoundException*/ FileReader fr = null; try { fr = new FileReader("demo.txt"); /*读取方法一:调用读取流对象的read方法 read()方法一次读一个字符,而且会自动往下读,已到末尾返回-1*/ int ch = 0; while ((ch=fr.read())!=-1) System.out.println((char)ch); /*读取方法二:定义一个字符串数组,用于存储读到字符。该read(char[]) 返回的是读到字符个数*/ char[] buf = new char[1024]; int num = 0; while ((num=fr.read(buf))!=-1) { System.out.println("num="+num+"..."+new String(buf,0,num)); } } catch (IOException e) { System.out.println(e.toString()); } finally { try { if(fr!=null) fr.close(); } catch (IOException e) { System.out.println(e.toString()); } } } }
3)拷贝文本文件
import java.io.*; class CopyText { public static void main(String[] args) { copy_2(); } //复制方式一:从C盘读一个字符,就往D盘写一个字符 public static void copy_1() { //创建目的地 FileWriter fw = null; //与已有文件关联 FileReader fr = null; try { fw = new FileWriter("RuntimeDemo_copy.txt"); fr = new FileReader("RuntimeDemo.java"); int ch = 0; while ((ch = fr.read())!=-1) { fw.write(ch); } } catch (IOException e) { throw new RuntimeException("读写失败"); } finally { try { if(fr!=null) fr.close(); } catch (IOException e) { throw new RuntimeException("读取关闭失败"); } finally { try { if(fw!=null) fw.close(); } catch (IOException e) { throw new RuntimeException("写入关闭失败"); } } } } //复制方式二:从C盘读取一段,再存到D盘中 public static void copy_2() { //创建目的地 FileWriter fw = null; //与已有文件关联 FileReader fr = null; try { fw = new FileWriter("SystemDemo_copy.txt"); fr = new FileReader("SystemDemo.java"); char[] buf = new char[1024]; int len = 0; while ((len = fr.read(buf))!=-1) { fw.write(buf,0,len); } } catch (IOException e) { throw new RuntimeException("读写失败"); } finally { try { if(fr!=null) fr.close(); } catch (IOException e) { throw new RuntimeException("读取关闭失败"); } finally { try { if(fw!=null) fw.close(); } catch (IOException e) { throw new RuntimeException("写入关闭失败"); } } } } }
11.3字符流的缓冲区
缓冲区的出现提高了对数据的读写效率,缓冲区要结合流才可以使用,在创建缓冲区之前,必须要先有流对象
1) BufferedWriter
该缓冲区中提供了一个跨平台的换行符:newLine();
import java.io.*; class BufferedWriterDemo { public static void main(String[] args) throws IOException { //创建一个字符写入流对象 FileWriter fw = new FileWriter("buf.txt"); /*为了提高字符写入流效率,加入缓冲技术,只要将需要被提高效率的流对象 作为参数传递给缓冲区的构造函数即可*/ BufferedWriter bufw = new BufferedWriter(fw); for (int x = 1;x<5 ;x++ ) { bufw.write("abcd"+x); bufw.newLine(); bufw.flush(); } //只要用到缓冲区,就要记得刷新 bufw.flush(); //关闭缓冲区就是在关闭缓冲区中的流对象 bufw.close(); } }
2) BufferedReader
该缓冲区提供了一个一次读一行的方法,方便于对文本数据的获取:readLine()。当返回null时表示读到文件末尾,返回的时候只返回回车符之前的数据内容。
import java.io.*; class BufferedReaderDemo { public static void main(String[] args) throws IOException { //创建一个读取流对象和文件相关联 FileReader fr = new FileReader("buf.txt"); /*为了提高效率,加入缓冲技术,将字符读取流对象 作为参数传递给缓冲对象的构造函数*/ BufferedReader bufr = new BufferedReader(fr); String line = null; while ((line = bufr.readLine())!=null) { System.out.println(line); } bufr.close(); } }
LineNumberReader类:是BufferedReader类的子类,有两个新方法
getLineNumber():获得当前行号
setLineNumber():设置当前行号
11.4装饰设计模式
当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能,并提供加强功能,那么自定义的该类称为装饰类
装饰类通常会通过构造方法接收被装饰的对象,并基于被装饰的对象的功能,提供更强的功能。
装饰模式比继承更灵活,避免了继承体系的臃肿,而且降低了类与类之间的关系。装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强的功能,所以装饰类和被装饰类通常都属于一个体系中。
装饰类和被装饰类都是,被装饰类父类的一个子类。创建自定义装饰类时,要继承父类,那么需要复写父类中的抽象方法
11.5字节流
1) FileInputSream (读)
public static void readFile_3() throws IOException { FileInputStream fis = new FileInputStream("fos.txt"); //定义一个刚刚好的缓冲区,不用再循环了,数据不大时使用。 byte[] buf = new byte[fis.available()]; //该文件可使用的容量 fis.read(buf); System.out.println(new String(buf)); fis.close(); } public static void readFile_2() throws IOException { FileInputStream fis = new FileInputStream("fos.txt"); byte[] buf = new byte[1024]; int len = 0; while((len=fis.read(buf))!=-1) { System.out.println(new String(buf,0,len)); } fis.close(); }
2) FileOutputSream (写)
public static void writeFile() throws IOException { FileOutputStream fos = new FileOutputStream("fos.txt"); //字节流不能写入字符串,通过String.getBytes()方法将字符串转成byte数组写入 fos.write("abcde".getBytes()); /*不需要flush()。因为字符流也是写入字节,但是需要将写入的字节先临时缓存。 查完表后通过flush()再写入字符。而字节流不需要缓存,直接就将字节写入*/ fos.close(); }
11.6字节流的缓冲区
BufferedOutputStream
BufferedInputStream
//通过缓冲区拷贝mp3文件: import java.io.*; class CopyMp3 { public static void main(String[] args) throws IOException { long start = System.currentTimeMillis(); copy_1(); long end = System.currentTimeMillis(); System.out.println((end-start)+"毫秒"); } //通过字节流缓冲区完成复制 public static void copy_1() throws IOException { BufferedInputStream bufis = <span style="white-space:pre"> </span>new BufferedInputStream(new FileInputStream("mp3.mp3")); BufferedOutputStream bufos = <span style="white-space:pre"> </span>new BufferedOutputStream(new FileOutputStream("mp3_copy.mp3")); int by = 0; while ((by=bufis.read())!=-1) { bufos.write(by); } bufos.close(); bufis.close(); } }
11.7读取键盘录入
System.in:对应的标准输入设备:键盘
1) InputStreamReader
是字节流通向字符流的桥梁,将字节流对象转成字符流对象。
2) OutputStreamWriter
字符流通向字节流的桥梁。
/*通过键盘录入数据,当录入一行数据后,就将该行数据进行打印 如果录入的数据是over,那么停止录入*/ import java.io.*; class ReadIn { public static void main(String[] args) throws IOException { //获取键盘录入对象 InputStream in =System.in; //将字节流对象转成字符流对象,使用转换流InputStreamReader InputStreamReader isr = new InputStreamReader(in); //为了提高效率,将字符流进行缓存区技术高效操作,使用BufferedReader BufferedReader bufr = new BufferedReader(isr); //获取输出对象 OutputStream out = System.out; //将字节流对象转成字符流对象,使用转换流OutputStreamWriter OutputStreamWriter osw = new OutputStreamWriter(out); BufferedWriter bufw = new BufferedWriter(osw); String line = null; while ((line=bufr.readLine())!=null) { if("over".equals(line)) break; bufw.write(line.toUpperCase()); bufw.newLine(); bufw.flush(); } bufr.close(); bufw.close(); } }
11.8流操作规律
1) 明确源和目的
源:输入流。InputStream Readerr
目的:输出流 OutputStream Writer
2) 操作的数据是否是纯文本
是:字符流
不是:字节流
3) 当体系明确后,再明确要使用哪个具体的对象
通过设备来进行区分
源设备:内存ArrayStream,硬盘 FileStream,键盘 System.in
目的设备:内存 ArrayStream,硬盘 FileStream,控制台 System.out
改变标准输入输出设备:
//将输入设备由键盘改成PersonDemo.java文件,需要建立一个字节流对象FileInputStream
System.setIn(new FileInputStream(“PersonDemo.java”))
//将输出设备由控制台改成zz.txt文件,需要建立一个字节输出流子类对象PrintStream
System.setOut(new PrintStream(“zz.txt”))
11.9File类
用来将文件或者文件夹封装成对象,方便对文件与文件夹的属性信息进行操作
File类常见方法:
1) 创建
boolean mkdir():创建文件夹,只能创建一级目录
boolean mkdirs():创建多级目录,包括所有必需但不存在的父目录
boolean createNewFile():在指定位置创建文件,如果该文件已经存在,则不创建,返回false。和输出流不一样,输出流对象一建立就会创建文件,而
且文件已经存在,会覆盖。File类要调用方法才创建文件。
2) 删除
boolean delete():如果此句前出现异常将不会执行到,文件就无法删除
void deleteOnExit():在程序退出时删除。在程序运行出现异常的时候也能删除文件。
3) 判断
boolean canExecute():判断文件是否可执行
boolean exists():判断文件是否存在
boolean isDirectory(): 判断文件对象是否是文件或者目录时,必须要先判断
boolean isFile(): 该文件对象封装的内容是否存在,通过exists判断
boolean isHidden():判断文件是否隐藏
4) 获取信息
getName()
getPath()
getParent() 该方法返回的是绝对路径中的父目录,如果File对象封装的是相对路径,返回null。如果相对路径中有上一层目录那么该目录就是返回结果
getAbsolutePath() 获取绝对路径
long lastModified() 获取文件最后被修改的时间
long length()
boolean renameTo() f1.renameTo(f2),变更文件名,还会将文件剪切到指定目录下
File[] listRoots() 列出可用的系统盘符
String[] list() 列出目录下的文件和子目录。调用list方法的file对象必须是封装了一个目录,该目录还必须存在
File[] listFiles() 列出目录下的文件,返回的是File对象的数组
列出指定目录下文件或者文件夹,包含子目录中的内容(带层次): import java.io.*; class FileDemo3 { public static void main(String[] args) { File file = new File("c:\\java001"); showDir(file,0); } public static void showDir(File dir,int level ) { System.out.println(getLevel(level)+dir.getName()); //level只对应于调用的函数中,递归调用时对应的是函数中相应的值 level++; File[] files = dir.listFiles(); for (int x = 0; x<files.length;x++ ) { //如果是文件夹,可以调用方法本身继续遍历文件夹 if(files[x].isDirectory()) showDir(files[x],level); else System.out.println(getLevel(level)+files[x].getName()); } } public static String getLevel(int level) { StringBuilder sb = new StringBuilder(); //文件夹及文件名前带|-- sb.append("|--"); for (int x=0;x<level ;x++ ) { //子级目录缩进 sb.insert(0," "); } return sb.toString(); } }
函数自身调用自身,这种表现形式称为递归。使用时需要注意:
1)限定条件
2)要注意递归的次数,尽量避免内存溢出
11.10Properties类
Properties是hashtable的子类,具备map集合的特点,它里面存储的键值对都是字符串。是集合中和IO技术相结合的集合容器。该对象的特点:可以用于键值对形式的配置文件。
Properties中的方法:
setProperty(String key, String value) 向集合中存入键值对
String getProperty(String key) 获取对应键的值
Set<String> stringPropertyNames() 获取Properties对象中键的集合
list(PrintStream out)
list(PrintWriter out)
load(InputStream inStream)
load(Reader reader)
store(OutputStream out, String comments) 将Properties中的键值对存储到配置文件中
store(Writer writer, String comments) 并且加入注释信息comments。
import java.io.*; import java.util.*; class PropertiesDemo { public static void main(String[] args) throws IOException { //method_1(); PropertiesMethod(); } //load,list,store方法应用 public static void PropertiesMethod() throws IOException { FileInputStream fis = new FileInputStream("Info.txt"); Properties prop = new Properties(); //将流中的数据加载进集合 prop.load(fis); //设置配置文件中的信息 prop.setProperty("wangwu","39"); FileOutputStream fos = new FileOutputStream("Info.txt"); prop.store(fos,"haha"); //将集合中的数据输出到流中 prop.list(System.out); fos.close(); fis.close(); } //load方法原理:将info.txt中键值数据存到集合中进行操作。 public static void method_1() throws IOException { BufferedReader bufr = new BufferedReader(new FileReader("Info.txt")); String line = null; Properties prop = new Properties(); while ((line=bufr.readLine())!=null) { //利用=将键与值分割 String[] arr = line.split("="); //调用方法将键和值存入到集合中 prop.setProperty(arr[0],arr[1]); } bufr.close(); } //设置和获取元素 public static void setAndGet() { Properties prop = new Properties(); prop.setProperty("zhangsan","30"); prop.setProperty("lisi","39"); String value = prop.getProperty("lisi"); System.out.println(value); Set<String> names = prop.stringPropertyNames(); for(String s : names) { System.out.println(s); } } }
11.11打印流
为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。该流提供了打印方法,可以将各种数据类型的数据都原样打印
字节打印流:
PrintStream
构造函数可以接收的参数类型:
1. file对象 File
2. 字符串路径 String
3. 字节输出流 OutputStream
字符打印流:
PrintWriter
构造函数可以接收的参数类型:
1. file对象 File
2. 字符串路径 String
3. 字节输出流 OutputStream
4. 字符输出流 Writer
PrintWriter(OutputStream out, booleanautoFlush) autoFlush为true时,println方法会
PrintWriter(Writer out, boolean autoFlush) 自动刷新缓存
11.12 序列流SequenceInputStream
SequenceInputStream表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。
import java.io.*; import java.util.*; class SequenceDemo { public static void main(String[] args) throws IOException { Vector<FileInputStream> v = new Vector<FileInputStream>(); v.add(new FileInputStream("1.txt")); v.add(new FileInputStream("2.txt")); v.add(new FileInputStream("3.txt")); Enumeration<FileInputStream> en = v.elements(); SequenceInputStream sis = new SequenceInputStream(en); FileOutputStream fos = new FileOutputStream("4.txt"); byte[] buf = new byte[1024]; int len = 0; while ((len=sis.read(buf))!=-1) { fos.write(buf,0,len); } fos.close(); sis.close(); } }
11.13对象的序列化
ObjectInputStream ObjectOutputStream
将堆内存中的对象存入的文件当中,对象内的变量数据也被保存;读取文件的可以读取到所存储的对象,直接调用之前的数据。实现了Serializable接口的对象才能被序列化。
在需要序列化的对象中添加static final long serialVersionUID = 42L语句,即使本地的该对象有所修改,也可以读取被序列化的对象,否则会报出InvalidClassException异常。
static 修饰的变量不能被序列化,因为static修饰的内容存在于方法区;transient修饰的变量也不能被序列化,即使变量存在于堆内存中。
11.14管道流
PipedInputStream PipedOutputStream
管道输入流和管道输出流通过不同线程运行。管道流是多线程和IO流的结合应用
import java.io.*; class Read implements Runnable { private PipedInputStream in; Read(PipedInputStream in) { this.in = in; } public void run() { try { byte[] buf = new byte[1024]; //当没有读取到数据时read方法会阻塞,即线程等待。 int len = in.read(buf); String s = new String(buf,0,len); System.out.println(s); in.close(); } catch (IOException e) { throw new RuntimeException("管道读取流失败"); } } } class Write implements Runnable { private PipedOutputStream out; Write(PipedOutputStream out) { this.out = out; } public void run() { try { out.write("piped lai le".getBytes()); out.close(); } catch (IOException e) { throw new RuntimeException("管道输出流失败"); } } } class PipedStreamDemo { public static void main(String[] args) throws IOException { PipedInputStream in = new PipedInputStream(); PipedOutputStream out = new PipedOutputStream(); in.connect(out); Read r = new Read(in); Write w = new Write(out); new Thread(r).start(); new Thread(w).start(); } }
11.15RandomAccessFile
该类不是IO体系中的子类,而是直接继承自Object。但是它是IO包中的成员,因为它具备读和写功能,内部封装了一个数组,而且通过指针对数组中的元素进行操作。可以通过getFilePointer获取指针位置,同时可以通过seek改变指针的位置。
能够完成读写的原理就是内部封装了字节输入流和输出流。该类只能操作文件,操作模式通常有只读r和读写rw。
如果模式为只读r,不会创建文件,会去读取一个已存在的文件,如果该文件不存在,则会出现异常。
如果模式为rw,操作的文件不存在,会自动创建;如果存在,则不会覆盖。
该类可以通过多个线程同时对一个文件进行读写操作,下载就是利用此原理
import java.io.*; class RandomAccessFileDemo { public static void main(String[] args) throws IOException { //writeFile2(); //writeFile(); //readFile(); } public static void readFile() throws IOException { RandomAccessFile raf = new RandomAccessFile("ran.txt","r"); //调整对象中的指针,来读取想要读取的内容,往前往后都能调整 //raf.seek(8); //跳过指定的字节数,来读取想要读取的内容,只能往后跳 //raf.skipBytes(8); byte[] buf = new byte[4]; raf.read(buf); String name = new String(buf); //从此文件读取一个有符号的 32 位整数 int age = raf.readInt(); System.out.println("name="+name); System.out.println("age="+age); raf.close(); } //向指定位置写入数据 public static void writeFile2() throws IOException { //创建对象时与输出流不同,不会覆盖已有文件 RandomAccessFile raf = new RandomAccessFile("ran.txt","rw"); raf.seek(8*3); raf.write("周期".getBytes()); raf.writeInt(103); raf.close(); } public static void writeFile() throws IOException { RandomAccessFile raf = new RandomAccessFile("ran.txt","rw"); raf.write("李四".getBytes()); //按4个字节写入int数字 raf.writeInt(97); raf.write("王五".getBytes()); raf.writeInt(99); raf.close(); } }
11.16DataStream
可以用于操作基本数据类型的数据的流对象
11.17ByteArrayStream
ByteArrayInputStream : 在构造的时候,需要接收数据源,而且数据源是一个字节数组
ByteArrayOutputStream : 在构造的时候,不用定义数据目的,因为该对象中已经内部封
装了可变长度的字节数组,这就是数据目的地
因为这两个流对象都操作的数组,并没有使用系统资源,所以不用进行close关闭
ByteArrayStream是用流的思想来操作数组
import java.io.*; class ByteArrayStream { public static void main(String[] args) { //数据源 ByteArrayInputStream bis = new ByteArrayInputStream("ABCDE".getBytes()); //数据目的 ByteArrayOutputStream bos = new ByteArrayOutputStream(); int by = 0; while ((by=bis.read())!=-1) { bos.write(by); } System.out.println(bos.toString()); //将字节数组输出流中的数据写入到一个文件当中 bos.writeTo(new FileOutputStream("a.txt")); } }
相关文章推荐
- Java 多线程面试问题汇总
- 《程序员面试宝典》 —— 多态的作用
- 黑马程序员——程序设计模式
- PHP笔记——java程序员看懂PHP程序
- 黑马程序员—Java集合框架及Java中的几个工具类
- 面试题35:第一个只出现一次的字符
- 黑马程序员————第二十天
- 黑马程序员——OC—类方法及匿名类
- 程序员必读的六本书
- 程序员必读的六本书 2015-07-08 11:26 21人阅读 评论(0) 收藏
- 黑马程序员——JAVA笔记——LOCK
- 国外程序员常去的14个顶级开发社区
- 【转载】2015Android 面试题 01
- 面试题45:圆圈中最后剩下的数字
- 大公司最喜欢问的Java集合类面试题
- 面试知识点总结01
- php相关问题学习(以备面试)
- 黑马程序员——OC—类和对象的使用
- [异能程序员]第一章 酒后事发,上头条
- 解析程序员的几个成长阶段