JAVA-IO学习(笔记)

JAVA-IO
一.InputStream
1. 类图
附件
2. 子类说明
流的数据方法都用了native实现方式,都不知道哪里去看实现。
2.1  ByteArrayInputStream
     把字节数组数据转化为输入流;通过byte数组实现数据的存取
     重要变量:
protected byte buf[];    //缓冲区数据
protected int pos;      //下一个读取字符的位置
protected int mark = 0;  //当前位置标记
protected int count;     //需要读入(或现有)数据长度


2.2  FileInputStream
从文件中读取数据,他的子类中有socketInputStream
重要变量:
            private FileDescriptor fd;   //文件描述,文件类型读取方式的记录 
     private FileChannel channel = null;  //文件的链接


2.3  PipedInputStream
    管道输入流应该连接到管道输出流;管道输入流提供要写入管道输出流的所有数据字节。通常,数据由某个线程从 PipedInputStream 对象读取,并由其他线程将其写入到相应的 PipedOutputStream。不建议对这两个对象尝试使用单个线程,因为这样可能死锁线程。管道输入流包含一个缓冲区,可在缓冲区限定的范围内将读操作和写操作分离开。如果向连接管道输出流提供数据字节的线程不再存在,则认为该管道已损坏

重要变量:
boolean closedByWriter = false;
             volatile boolean closedByReader = false;
             boolean connected = false;
             Thread readSide;     //当前读线程
    		 Thread writeSide;    //当前写线程
     		 protected byte buffer[] = new byte[PIPE_SIZE]; //缓冲区数据 初始PIPE_SIZE=1024
             通过标记closedByWriter  closedByReader  可以对当前数据进行锁处理,

             例子:
--------------------------写数据--------------------------------
public class RunPipedMain {

    public static void main(String... strings) {
        ReceiverThread read = new ReceiverThread();
        WriterThread write = new WriterThread();
        PipedInputStream in = read.getIn();
        PipedOutputStream out = write.getOut();
        try {
            out.connect(in);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        write.start();

        read.start();
    }
}
--------------------------接受--------------------------------
public class ReceiverThread extends Thread {

    private PipedInputStream in;

    public PipedInputStream getIn() {
        if (in == null) in = new PipedInputStream();
        return in;
    }

    public void run() {
        System.out.println("read..............");
        byte[] buf = new byte[1024]; // 字节数组
        try { // read和close方法都可能有异常出现
            int len = in.read(buf); // 读取数据,len表示实际读取到的内容(长度)
            System.out.println("the following message comes from sender:\n" + new String(buf, 0, len));
            in.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

--------------------------运行---------------------------------
public class RunPipedMain {

    public static void main(String... strings) {
        ReceiverThread read = new ReceiverThread();
        WriterThread write = new WriterThread();
        PipedInputStream in = read.getIn();
        PipedOutputStream out = write.getOut();
        try {
            out.connect(in);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        write.start();

        read.start();
    }
}
--------------------------运行结果--------------------------------
1.  write..............
2.  read..............
3.  the following message comes from sender:
4.  test out...........
问1:看着结果,我想到一点,为什么不论是哪个线程先运行,都会先写后读呢?
即运行结果中1, 2两步的运行顺序是不可确定的。  难道pipedInputStream会去等待么?

查看代码中: pipedInputStream中read()方法,通过判断connected变来,知道当前是否连接,如果链接则判断closedByWriter变量,看是否已经被out给关闭,然后如果没有关闭的话,判断in变量是否小于0(小于0代表数据还没读到),小于0就wait(1000),大于零就开始取数据:
代码如下:
  
public synchronized int read()  throws IOException {
        if (!connected) {
            throw new IOException("Pipe not connected");
        } else if (closedByReader) {
	    throw new IOException("Pipe closed");
	} else if (writeSide != null && !writeSide.isAlive()
                   && !closedByWriter && (in < 0)) {
            throw new IOException("Write end dead");
        }

        readSide = Thread.currentThread();
	int trials = 2;
	while (in < 0) {
	    if (closedByWriter) {
		/* closed by writer, return EOF */
		return -1;
	    }
	    if ((writeSide != null) && (!writeSide.isAlive()) && (--trials < 0)) {
		throw new IOException("Pipe broken");
	    }
            /* might be a writer waiting */
	    notifyAll();
	    try {
	        wait(1000);
	    } catch (InterruptedException ex) {
		throw new java.io.InterruptedIOException();
	    }
 	}
	int ret = buffer[out++] & 0xFF;
	if (out >= buffer.length) {
	    out = 0;
	}
	if (in == out) {
            /* now empty */
	    in = -1;
	}
	return ret;
}

问2:  in和 out变量是什么时候修改的?


2.4  SequenceInputStream
SequenceInputStream 表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。

重要变量:
               
  Enumeration e;  //存取InputStream的枚举类
    InputStream in;  //枚举类中,当前的InputStream对象

    他是通过传入Enumeration,在之间取到Enumeration,进行IO操作。

例子:
public class EnumerationInputStreamTest {

    Enumeration         e    = null;       // 由内部类实现,如Vector
    String              sss  = "testsetst";
    SequenceInputStream seq  = null;
    Vector              coll = null;

    public void test() {
        try {
            FileInputStream file = new FileInputStream("c:\\boot.ini");
            ByteArrayInputStream byteArray = new ByteArrayInputStream(sss.getBytes());
            coll = new Vector();
            coll.add(byteArray);
            coll.add(file);
            e = ((Vector) coll).elements();
            seq = new SequenceInputStream(e);
            int i = 0;
            while (i != -1) {
                i = seq.read();
                System.out.println("out:" + i);
            }
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public static void main(String... strings) {
        EnumerationInputStreamTest eee = new EnumerationInputStreamTest();
        eee.test();
    }
}

运行结果: 
out:116
out:101
out:115
…
out:13
out:-1 


2.5  ObjectInputStream
   这里转一下网上的文章,感觉写的不错。
源文件地址:
http://hi.baidu.com/mdbing/blog/item/4612cb13decfc4075aaf53fa.html
      Java程序执行的过程中,很多数据都是以对 象的方式存在于内存中。有时会希望直接将内存中整个对象存储至文件,而不是只存储对象中的某些基本类型成员信息,而在下一次程序运行时,希望可以从文件中 读出数据并还原为对象。这时可以使用java.io.ObjectInputStream和java.io.ObjectOutputStream来进行 这项工作
      如果要直接存储对象,定义该对象的类必须实现java.io.Serializable接口,不过Serializable接口中并没有规范任何必须实现的方法,所以这里所谓实现的意义,其实像是对对象贴上一个标志,代表该对象是可序列化的(Serializable)。
      为了说明如何直接存储对象,先来实现一个User类
Java代码
import java.io.Serializable;   
  
public class User implements Serializable {    
    private static final long serialVersionUID = 1L;    
    private String name;    
    private int number;    
    public User() {    
    }    
    public User(String name, int number) {   
        this.name = name;   
        this.number = number;   
    }    
    public String getName() {   
        return name;   
    }    
    public void setName(String name) {   
        this.name = name;   
    }    
    public int getNumber() {   
        return number;   
    }    
    public void setNumber(int number) {   
        this.number = number;   
    }    
}  
import java.io.Serializable; 
public class User implements Serializable { 
	private static final long serialVersionUID = 1L; 
	private String name; 
	private int number; 
	public User() { 
	} 

	public User(String name, int number) {
		this.name = name;
		this.number = number;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getNumber() {
		return number;
	}

	public void setNumber(int number) {
		this.number = number;
	}

}

注意到serialVersionUID,它代 表了可序列化对象的版本。如果没有提供这个版本信息,则实现Serializable接口的类会自动依类名称、实现的接口、成员等来产生。如果是自动产生 的,则下次更改User类,自动产生的serialVersionUID也会跟着变更,从文件读回对象时若两个对象的serialVersionUID不 相同,就会丢出java.io.InvalidClassException。如果想要维持版本信息的一致,则要明确声明 serialVersionUID。
ObjectInputStream和 ObjectOutputStream为InputStream、OutputStream的实例加上了可以让用户写入对象与读出对象的功能。在写入对象 时,要使用writeObject()方法,读出对象时则使用readObject()方法,被读出的对象都是以Object的类型返回。所以必须将之转 换为对象原来的类型,才能正确地实现被读回的对象。示范了如何存储User对象至文件中,然后再将它读回并还原为User实例
Java代码
import java.io.File;   
import java.io.FileInputStream;   
import java.io.FileNotFoundException;   
import java.io.FileOutputStream;   
import java.io.IOException;   
import java.io.ObjectInputStream;   
import java.io.ObjectOutputStream;   
import java.util.ArrayList;   
import java.util.List;   
  
public class ObjectStreamDemo {   
  
    public static void main(String args[]) {   
        User[] users = { new User("cater", 101), new User("justin", 102) };   
        // 写入新文件   
        writeObjectsToFile(users, args[0]);   
        try {   
            // 读取文件数据   
            users = readObjectsFromFile(args[0]);   
            // 显示读回的对象   
            for (User user : users) {   
                System.out.printf("%s\t%d%n", user.getName(), user.getNumber());   
            }   
            System.out.println();   
  
            users = new User[2];   
            users[0] = new User("momor", 103);   
            users[1] = new User("becky", 104);   
  
            // 附加新对象至文件   
            appendObjectsToFile(users, args[0]);   
  
            // 读取文件数据   
            users = readObjectsFromFile(args[0]);   
            // 显示读回的对象   
            for (User user : users) {   
                System.out.printf("%s\t%d\n", user.getName(), user.getNumber());   
            }   
  
        } catch (ArrayIndexOutOfBoundsException e) {   
            e.printStackTrace();   
        } catch (FileNotFoundException e) {   
            e.printStackTrace();   
        }   
    }   
  
    public static void writeObjectsToFile(Object[] objs, String filename) {   
        File file = new File(filename);   
        try {   
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(   
                    new FileOutputStream(file));   
            for (Object obj : objs) {   
                // 将对象写入文件   
                objectOutputStream.writeObject(obj);   
            }   
            objectOutputStream.close();   
        } catch (FileNotFoundException e) {   
            e.printStackTrace();   
        } catch (IOException e) {   
            // TODO Auto-generated catch block   
            e.printStackTrace();   
        }   
    }   
  
    public static User[] readObjectsFromFile(String fileName)   
            throws FileNotFoundException {   
        File file = new File(fileName);   
        // 如果文件不存在就丢出异常   
        if (!file.exists())   
            throw new FileNotFoundException("未找到文件" + fileName);   
        // 使用List先读取出对象   
        List<User> list = new ArrayList();   
        try {   
            FileInputStream fileInputStream = new FileInputStream(file);   
            ObjectInputStream objectInputStream = new ObjectInputStream(   
                    fileInputStream);   
            while (fileInputStream.available() > 0) {   
                list.add((User) objectInputStream.readObject());   
            }   
            objectInputStream.close();   
  
        } catch (IOException e) {   
            e.printStackTrace();   
        } catch (ClassNotFoundException e) {   
            // TODO Auto-generated catch block   
            e.printStackTrace();   
        }   
        User[] users = new User[list.size()];   
        return list.toArray(users);   
    }   
  
    public static void appendObjectsToFile(Object[] objs, String fileName)   
            throws FileNotFoundException {   
        File file = new File(fileName);   
        if (!file.exists())   
            throw new FileNotFoundException("未发现文件" + fileName);   
        try {   
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(   
                    new FileOutputStream(fileName, true)) {   
                // 如果要附加对象到文件后   
                // 必须重新定义这个方法   
                protected void writeStreamHeader() throws IOException {   
                }   
            };   
            for (Object obj : objs) {   
                objectOutputStream.writeObject(obj);   
            }   
            objectOutputStream.close();   
  
        } catch (IOException e) {   
            e.printStackTrace();   
        }   
  
    }   
}  
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;

public class ObjectStreamDemo {

	public static void main(String args[]) {
		User[] users = { new User("cater", 101), new User("justin", 102) };
		// 写入新文件
		writeObjectsToFile(users, args[0]);
		try {
			// 读取文件数据
			users = readObjectsFromFile(args[0]);
			// 显示读回的对象
			for (User user : users) {
				System.out.printf("%s\t%d%n", user.getName(), user.getNumber());
			}
			System.out.println();

			users = new User[2];
			users[0] = new User("momor", 103);
			users[1] = new User("becky", 104);

			// 附加新对象至文件
			appendObjectsToFile(users, args[0]);

			// 读取文件数据
			users = readObjectsFromFile(args[0]);
			// 显示读回的对象
			for (User user : users) {
				System.out.printf("%s\t%d\n", user.getName(), user.getNumber());
			}

		} catch (ArrayIndexOutOfBoundsException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}

	public static void writeObjectsToFile(Object[] objs, String filename) {
		File file = new File(filename);
		try {
			ObjectOutputStream objectOutputStream = new ObjectOutputStream(
					new FileOutputStream(file));
			for (Object obj : objs) {
				// 将对象写入文件
				objectOutputStream.writeObject(obj);
			}
			objectOutputStream.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public static User[] readObjectsFromFile(String fileName)
			throws FileNotFoundException {
		File file = new File(fileName);
		// 如果文件不存在就丢出异常
		if (!file.exists())
			throw new FileNotFoundException("未找到文件" + fileName);
		// 使用List先读取出对象
		List<User> list = new ArrayList();
		try {
			FileInputStream fileInputStream = new FileInputStream(file);
			ObjectInputStream objectInputStream = new ObjectInputStream(
					fileInputStream);
			while (fileInputStream.available() > 0) {
				list.add((User) objectInputStream.readObject());
			}
			objectInputStream.close();

		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		User[] users = new User[list.size()];
		return list.toArray(users);
	}

	public static void appendObjectsToFile(Object[] objs, String fileName)
			throws FileNotFoundException {
		File file = new File(fileName);
		if (!file.exists())
			throw new FileNotFoundException("未发现文件" + fileName);
		try {
			ObjectOutputStream objectOutputStream = new ObjectOutputStream(
					new FileOutputStream(fileName, true)) {
				// 如果要附加对象到文件后
				// 必须重新定义这个方法
				protected void writeStreamHeader() throws IOException {
				}
			};
			for (Object obj : objs) {
				objectOutputStream.writeObject(obj);
			}
			objectOutputStream.close();

		} catch (IOException e) {
			e.printStackTrace();
		}

	}
} 
范例中必要的地方都已加上注释,虽然程序很长,但范例中已经将写入对象至文件、从文件读出对象、附加对象至文件的程序逻辑集中在writeObjectsToFile()、readObjectsFromFile()与appendObjectsToFile() 3个方法中

Java代码
ObjectOutputStream objOutputStream =   
     new ObjectOutputStream(   
         new FileOutputStream(file, true)) {   
             protected void writeStreamHeader()   
                                  throws IOException {}   
         };  


2.6  BufferedInputStream
BufferedInputStream 为另一个输入流添加一些功能,即缓冲输入以及支持 mark 和 reset 方法的能力。在创建 BufferedInputStream 时,会创建一个内部缓冲区数组。在读取或跳过流中的字节时,可根据需要从包含的输入流再次填充该内部缓冲区,一次填充多个字节。mark 操作记录输入流中的某个点,reset 操作使得在从包含的输入流中获取新字节之前,再次读取自最后一次 mark 操作后读取的所有字节。
修改上面代码 :
public class EnumerationInputStreamTest {

    Enumeration         e    = null;       // 由内部类实现,如Vector
    String              sss  = "testsetst";
    SequenceInputStream seq  = null;
    Vector              coll = null;

    public void test() {
        try {
            long begin = System.currentTimeMillis();
            System.out.println("开始::" + begin);
            FileInputStream file = new FileInputStream("c:\\boot.ini");
            BufferedInputStream fileBuffer = new BufferedInputStream(file);
            ByteArrayInputStream byteArray = new ByteArrayInputStream(sss.getBytes());
            BufferedInputStream byteArrayBuffer = new BufferedInputStream(byteArray);
            coll = new Vector();
            coll.add(fileBuffer);
            coll.add(byteArrayBuffer);
            e = ((Vector) coll).elements();
            seq = new SequenceInputStream(e);
            int i = 0;
            while (i != -1) {
                i = seq.read();
                System.out.println("out:" + i);
            }
            long end = System.currentTimeMillis();
            System.out.println("结束::" + end);
            System.out.println("耗时::" + (end - begin));
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public static void main(String... strings) {
        EnumerationInputStreamTest eee = new EnumerationInputStreamTest();
        eee.test();
    }
}

运行结果:
开始::1226545776404
out:91
out:98
                    …
out:-1	
结束::1226545776419
耗时::15

2.7  PushbackInputStream
  用作缓冲数据,需要时可以将数据重新塞回流里面,相当于做了一个拦截和处理。
例子:

public class PushBackTest {

    String sss = "testsetst";
    int    res[];
    byte   byteArray[];

    public void test() {
        try {
            long begin = System.currentTimeMillis();
            System.out.println("开始::" + begin);
            ByteArrayInputStream byteArrayStream = new ByteArrayInputStream("这只是个测试啊".getBytes());
            BufferedInputStream byteArrayBuffer = new BufferedInputStream(byteArrayStream);
            /*
             * 这里必要时要设置pushback区大小,默认是1,如果长度太大,则会返回 java.io.IOException: Push back buffer is full 异常
             */
            PushbackInputStream filePBack = new PushbackInputStream(byteArrayBuffer, 1024);

            int intAvai = 0;
            intAvai = filePBack.available();
            System.out.println("intAvai:" + intAvai);
            res = new int[intAvai + 1];
            byteArray = new byte[intAvai];
            int i = 0;
            int j = 0;
            while ((i = filePBack.read()) != -1) {
                byteArray[j] = (byte) i;
                System.out.println("out:" + i);
                j++;
            }
            long end = System.currentTimeMillis();
            System.out.println("结束::" + end);
            System.out.println("耗时::" + (end - begin));
            // ===================================
            System.out.println("获取到的::" + byteArray);
            filePBack.unread(byteArray);
            i = 0;
            System.out.println("filePBack.available():" + filePBack.available());
            begin = System.currentTimeMillis();
            System.out.println("重新开始::" + begin);

            byte[] array = new byte[2];
            int tmp = 0;
            int count = 0;
            while ((i = filePBack.read(array)) != -1) {
                // 两个字节转换为整数
                tmp = (short) ((array[0] << 8) | (array[1] & 0xff));

                tmp = tmp & 0xFFFF;

                // 判断是否为BIG5,如果是则显示BIG5中文字
                if (tmp > 0xA440 && tmp < 0xFFFF) {
                    System.out.println("BIG5:" + new String(array));
                } else {
                    // 将第二个字节流推回
                    if (count == 2) {
                        filePBack.unread(array, 1, 1);
                    }
                    // 显示ASII范围的字符
                    System.out.println("ASCII:" + (char) array[0]);
                }
            }
            end = System.currentTimeMillis();
            System.out.println("又结束::" + end);
            System.out.println("再次耗时::" + (end - begin));
             byteArrayStream.close();
            byteArrayBuffer.close();
            filePBack.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public static void main(String... strings) {
        PushBackTest eee = new PushBackTest();
        eee.test();
    }
}

运行结果:
开始::1226561001499
…
结束::1226561001499
耗时::0 
…
重新开始::1226561001499
BIG5:这
BIG5:只
BIG5:是
BIG5:个
BIG5:测
BIG5:试
BIG5:啊
又结束::1226561001499
再次耗时::0

3. 深入理解


二.OutputStream

三.Reader

四.Writer

你可能感兴趣的:(java,thread,Blog,J#)