java i/o原理
基本概念:
- I/O(Input/Output)
- 数据源(Data Source)
- 数据宿(Data Sink)
Java中把不同的数据源与程序间的数据传输都抽象表述为"流"(Stream),java.io包中定义了多种I/O流类型实现数据I/O功能。
I/O流分类:
- 输入流(Input Stream)和输出流(Output Stream)
- 节点流(Node Stream)和处理流(Processing Stream)
- 字符流(Character Stream)和字节流(Byte Stream)
输入流和输出流
按照数据流动的方向,java流可分为输入流(Input Stream)和输出流(Output Stream)
- 输入流只能从中读取数据,而不能向其写出数据;
- 输出流则只能向其写出数据,而不能从中读取数据
- 特例:java.io.RandomAccessFile类
节点流和处理流
根据数据流所关联的是数据源还是其他数据流,可分为节点流(Node Stream)和处理流(Processing Stream)
字符流和字节流
按传输数据的"颗粒大小"划分,可分为字符流(Character Stream)和字节流(Byte Stream)
- 字节流以字节为单位进行数据传输,每次传送一个或多个字节;
- 字符流以字符为单位进行数据传输,每次传送一个或多个字符.
Java命名惯例:
凡是以InputStream或OutputStream结尾的类型均为字节流,凡是以Reader或Writer结尾的均为字符流。
InputStream
抽象类java.io.InputStream是所有字节输入流类型的父类,该类中定义了以字节为单位读取数据的基本方法,并在其子类中进行了分化和实现.
三个基本的read方法:
- int read()
- int read(byte[] buffer)
- int read(byte[] buffer,int offset,int length)
其他方法:
- void close()
- int available()
- skip(long n)
- boolean markSupported()
InputStream类层次
OutputStream
java.io.OutputStream与java.io.InputStream对应,是所有字节输出流类型的抽象父类。
三个基本的write方法:
- void write(int c)
- void write(byte[] buffer)
- void write(byte[] buffer,int offset,int length)
其他方法:
- void close()
- void flush()
OutputStream类层次
Reader
抽象类java.io.Reader是所有字符输入流类型的父类,其中声明了用于读取字符流的有关方法.
三个基本的read方法:
- int read()
- int read(char[] cbuf)
- int read(char[] cbuf,int offset,int length)
其他方法:
- void close()
- boolean ready()
- skip(long n)
- boolean markSupported()
- void mark(int readAheadLimit)
- void reset()
Reader类层次
Writer
java.io.Writer与java.io.Reader类对应,是所有字符输出流类型的共同父类.
五个基本的write方法:
- void write(int c)
- void write(char[] cbuf)
- void write(char[] cbuf,int offset,int leng)
- void write(String string)
- void write(String string,int offset,int length)
其它方法:
- void close()
- void flush()
Writer类层次
常用I/O流类型
FileInputStream/FileOutputStream
FileInputStream用于读取本地文件中字节数据,FileOutputStram用于将字节数据写到文件.
使用字节流实现文件的复制
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import java.io.IOException;
- public class CopyFile{
- public static void main(String[] args) {
- try {
- FileInputStream fis = new FileInputStream ("a.jpg");
- FileOutputStream fos = new FileOutputStream ("temp.jpg");
- int read = fis.read();
- while ( read != -1 ) {
- fos.write(read);
- read = fis.read();
- }
- fis.close();
- fos.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
FileReader/FileWriter
FileReader用于以字符为单位读取文本文件,FileWriter类用于将字符数据写到文本文件中
使用字符流实现文件的复制
- import java.io.*;
- public class Test {
- public static void main(String[] args) {
- try {
- FileReader input = new FileReader("a.txt");
- FileWriter output = new FileWriter("temp.txt");
- int read = input.read();
- while ( read != -1 ) {
- output.write(read);
- read = input.read();
- }
- input.close();
- output.close();
- } catch (IOException e) {
- System.out.println(e);
- }
- }
- }
BufferedReader/BufferedWriter
BufferedReader用于缓冲读取字符,BufferedWriter则是供字符的缓存写出功能.
使用字符处理流实现文件的复制
- import java.io.*;
- public class Test {
- public static void main(String[] args) {
- try {
- FileReader input = new FileReader("Test.java");
- BufferedReader br = new BufferedReader(input);
- FileWriter output = new FileWriter("temp.txt");
- BufferedWriter bw = new BufferedWriter(output);
- String s = br.readLine();
- while ( s!=null ) {
- bw.write(s);
- bw.newLine();
- s = br.readLine();
- }
- br.close();
- bw.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
InputStreamReader
- InputStreamReader可封装字节输入流并从中读取字节数据,然后将之转换为字符.
- 转换时所使用的字符编码可以在构造方法中显示指定,也可以使用平台的默认字符编码,其构造方法格式为:
- public InputStreamReader(InputStream in)
- public InputStreamReader(InputStream in,String enc)
OutputStream Writer
- 与InputStreamReader对应,OutputStreamWriter可按照特定的字符编码规则把字符转化为字节并写出到它所封装的字节输出流.
PrintStream
- PrintStream在OutputStream基础之上提供了增强的功能,即可以方便地输出各种类型数据(而不仅限于byte型)的格式化表示形式.
- PrintStream的方法从不抛出IOException
PrintWriter
- PrintWriter提供了PrintStream的所有打印方法,其方法也从不抛出IOException、
- 与PrintStream的区别:作为处理流使用时,PrintStream只能封装OutputStream类型的字节流,而PrintWriter既可以封装OutputStream,还能够封装writer类型字符输出流并增强其功能
DataInputStream/DataOutputStream
- 二者分别实现DataInput/DataOutput接口
- DataInputStream能够以一种与机器无关的方式,直接从底层字节输入流读取java基本类型和String类型的数据.
- DataOutputStream则能够直接将java基本类型和String类型数据写出到其他的字节输出流。
- import java.io.*;
- public class Test{
- public static void main(String args[]){
- try{
- FileOutputStream fos;
- DataOutputStream dos;
- FileInputStream fis;
- DataInputStream dis;
- fos = new FileOutputStream("myfile.data");
- dos = new DataOutputStream(fos);
- dos.writeUTF("休.格兰特");
- dos.writeInt(40);
- dos.close();
- fis = new FileInputStream("myfile.data");
- dis = new DataInputStream(fis);
- System.out.println("name:" + dis.readUTF());
- System.out.println("age:" + dis.readInt());
- fis.close();
- }catch(IOException e){
- System.out.println(e);
- }
- }
- }
CharArrayReader/CharArrayWriter
- charArrayReader实现了一个可用作字符输入流的字符缓冲区.
- CharArrayWriter实现了一个可当做Writer使用的字符输出缓存区.
- import java.io.*;
- public class MyReader{
- public void getInfo(Reader reader){
- try{
- int b = reader.read();
- while(b != -1){
- System.out.print((char)b);
- b = reader.read();
- }
- System.out.println();
- }catch(IOException e){
- e.printStackTrace();
- }
- }
- }
- import java.io.*;
- public class TestCharArrayReader{
- public static void main(String[] args){
- char[] b = {'I',' ','a','m',' ','S','a','i','l','i','n','g','!'};
- CharArrayReader car = new CharArrayReader(b);
- MyReader mr = new MyReader();
- mr.getInfo(car);
- }
- }
- import java.io.*;
- import java.util.Date;
- public class TestCharArrayWriter{
- public static void main(String[] args){
- try{
- BufferedReader br = new BufferedReader(new FileReader("a.txt"));
- String s ;
- while((s=br.readLine()) != null){
- System.out.println(s);
- }
- }catch(IOException e){
- CharArrayWriter cw = new CharArrayWriter();
- PrintWriter pw = new PrintWriter(cw,true);
- e.printStackTrace(pw);
- //char[] ca = cw.toCharArray();
- String info = cw.toString();
- Date time = new Date();
- //将time和info信息写入数据库---
- System.out.println("出错时间: " + time);
- System.out.println("错误信息:\n" + info);
- }
- }
- }
标准I/O重定向
标准输入重定向
- import java.io.*;
- public class TestSetInput{
- public static void main(String[] args){
- try{
- //FileInputStream fis = new FileInputStream("source.txt");
- //System.setIn(fis);
- int avg = 0;
- int total = 0;
- int count = 0;
- int num = 0;
- int i;
- BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
- String s = br.readLine();
- while(s != null && !s.equals("over")){
- i = Integer.parseInt(s);
- num++;
- total += i;
- avg = total/num;
- System.out.println("num=" + num + "\ttotal=" + total + "\tavg=" + avg);
- s = br.readLine();
- }
- }catch(Exception e){
- e.printStackTrace();
- }
- }
- }
标准输出/标准错误输出重定向
- import java.io.*;
- import java.util.Date;
- public class TestSetOutput{
- public static void main(String[] args){
- PrintStream ps = null;
- PrintStream ps_error = null;
- try{
- ps = new PrintStream(new FileOutputStream("output.txt",true));
- System.setOut(ps);
- ps_error = new PrintStream(new FileOutputStream("errorLog.txt",true));
- System.setErr(ps_error);
- int avg = 0;
- int total = 0;
- int count = 0;
- int num = 0;
- int i;
- BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
- String s = br.readLine();
- while(s != null && !s.equals("over")){
- i = Integer.parseInt(s);
- num++;
- total += i;
- avg = total/num;
- System.out.println("num=" + num + "\ttotal=" + total + "\tavg=" + avg);
- s = br.readLine();
- }
- }catch(Exception e){
- System.err.println("出错时间: " + new Date());
- System.err.print("错误信息:");
- e.printStackTrace(System.err);
- }finally{
- try{
- ps.close();
- ps_error.close();
- }catch(Exception e1){
- System.err.println("出错时间: " + new Date());
- System.err.print("错误信息:");
- e1.printStackTrace(System.err);
- }
- }
- }
- }
属性导出/导入
- import java.io.*;
- import java.util.Properties;
- public class LoadProperties{
- public static void main(String[] args){
- try{
- Properties ps = new Properties();
- FileReader fr = new FileReader("props.txt");
- ps.load(fr);
- fr.close();
- ps.list(System.out);
- }catch(Exception e){
- e.printStackTrace();
- }
- }
- }
- import java.io.*;
- import java.util.Properties;
- public class SaveProperties{
- public static void main(String[] args){
- try{
- Properties ps = new Properties();
- ps.setProperty("name","Scott");
- ps.setProperty("password","Tiger");
- FileWriter fw = new FileWriter("props.txt");
- ps.store(fw,"loginfo");
- fw.close();
- }catch(Exception e){
- e.printStackTrace();
- }
- }
- }
实现文件随即存/取操作
- import java.io.File;
- import java.io.IOException;
- import java.io.RandomAccessFile;
- public class TestRandomAccessFile{
- private File file;
- public static void main(String[] args){
- TestRandomAccessFile traf = new TestRandomAccessFile();
- traf.init();
- traf.record("Billy",22);
- traf.listAllRecords();
- }
- public void record(String record_breaker, int times){
- try{
- RandomAccessFile raf = new RandomAccessFile(file,"rw");
- boolean flag = false;
- while(raf.getFilePointer() < raf.length()){
- String name = raf.readUTF();
- if(record_breaker.equals(name)){
- raf.writeInt(times);
- flag = true;
- break;
- }else{
- raf.skipBytes(4);
- }
- }
- if(!flag){
- raf.writeUTF(record_breaker);
- raf.writeInt(times);
- }
- raf.close();
- }catch(Exception e){
- e.printStackTrace();
- }
- }
- public void init(){
- if(file == null){
- file = new File("record.txt");
- try{
- file.createNewFile();
- }catch(IOException e){
- e.printStackTrace();
- }
- }
- }
- public void listAllRecords(){
- try{
- RandomAccessFile raf = new RandomAccessFile(file,"r");
- while(raf.getFilePointer() < raf.length()){
- String name = raf.readUTF();
- int times = raf.readInt();
- System.out.println("name:" + name + "\trecord:" + times);
- }
- raf.close();
- }catch(Exception e){
- e.printStackTrace();
- }
- }
- }
使用临时文件
- import java.io.*;
- import java.awt.event.*;
- import javax.swing.*;
- public class TestTempFile implements ActionListener{
- private File tempPath;
- public static void main(String args[]){
- TestTempFile ttf = new TestTempFile();
- ttf.init();
- ttf.createUI();
- }
- public void createUI(){
- JFrame frame = new JFrame();
- JButton jb = new JButton("创建临时文件");
- jb.addActionListener(this);
- frame.add(jb,"North");
- frame.setSize(200,100);
- frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- frame.setVisible(true);
- }
- public void init(){
- tempPath = new File("temp");
- if(!tempPath.exists() || !tempPath.isDirectory()){
- tempPath.mkdir(); //如果不存在,则创建该文件夹
- }
- }
- public void actionPerformed(ActionEvent e){
- try {
- //在tempPath路径下创建临时文件"mytempfileXXXX.tmp"
- //XXXX 是系统自动产生的随机数, tempPath对应的路径应事先存在
- File tempFile=File.createTempFile("mytempfile",".txt",null);
- System.out.println(tempFile.getAbsolutePath());
- FileWriter fout=new FileWriter(tempFile);
- PrintWriter out=new PrintWriter(fout);
- out.println("some info!" );
- out.close(); //注意:如无此关闭语句,文件将不能删除
- //tempFile.delete();
- tempFile.deleteOnExit();
- }
- catch(IOException e1){
- System.out.println(e1);
- }
- }
- }
对象序列化
基本概念
- 对象的持久性(Object Persistance)长久保持一个对象的状态并在需要时获取该对象的信息以重新构造一个状态完全相同的对象
- 对象序列化(Object Serialization)通过写出对象的状态数据来记录一个对象
- 对象序列化的主要任务,写出对象信息,并遍历该对象对象的引用,从而建立一个完整的序列化流。
实现对象序列化
要序列化一个对象,其所属的类必须实现一些两种接口之一:
java.io.Serializable
java.io.Externalizable
java.io.ObjectOutputStream/ObjectInputStream类分别提供了对象的序列化和反序列化功能。
对象序列化APi层次
对象序列化过程中的数据保护
标记性接口Serializable
在对象序列化过程中,其所属类的static属性和方法代码不会被序列化处理.
对于个别不希望被序列化的非static属性,可以在属性声明时使用transient关键字进行标明.