Java io详解

来源:互联网 发布:好看的纪录片 知乎 编辑:程序博客网 时间:2024/05/29 19:41
流的本质是数据传输,根据数据传输特点抽象为不同的流对象,方便直观地进行数据操作。

根据处理的数据类型分为字节流和字符流。
字节流以字节(8bit)为单位,字符流以字符为单位。字节流能处理所有类型的数据(如图片,视频等),而字符流只能处理字符类型的数据。

1、InputStream
InputStream是所有输入字节流的父类,是一个抽象类。

ByteArrayInputStream,StringBufferInputStream(已弃用Deprecated,用StringReader代替),FileInputStream是三种基本的介质流,分别从Byte数组、StringBuffer和本地文件中读取数据。PipedInputSteam是从与其它线程共用的管道中读取数据。SequenceInputStream是把多个inputStream合成一个InputStream。而FilterInputStream和所有的FilterInputStream的子类都是装饰者模式(设计模式)中的装饰类。FilterInputStream的子类不能单独使用。

1.1、FilterInputStream
FilterInputStream类的构造方法是protected的,所以我们不直接使用此类,而是使用它的子类。在FilterInputStream中的子类有:
    BufferedInputStream  (在内存中创建一个默认值8KB字节大小的缓冲区进行字节流读操作)
    DataInputStream     (能以一种与机器无关的方式,直接从字节流中读取JAVA基本类型和String类型的数据,常用于网络传输)
    LineNumberInputStream (Deprecated 建立带有行功能过滤输入流)
    PushbackInputStream (拥有一个Puchback缓冲区,若缓冲区没有满,则可以使用unread方法将数据推回流的前端,一般用于检测字节流错误)
还有诸如CheckedInputStream、DigestInputStream等,这里不展开,有需要可以自行查阅API。

2、OutputStream
而OutputStream是所有输出字节流的父类,是一个抽象类。



与InputStream相基本相对应,ByteArrayOutputStream和FileOutputStream是两种基本的介质流,分别向Byte数组和本地文件中写入数据。PipedOutputStream是与其它线程共用的管道中写入数据。而FilterOutputStream和FilterOutputStream的子类都是装饰者模式(设计模式)中的装饰类。

2.1、FilterOutputStream
FilterOutputStream类也是一个protected的类,所以不能直接使用该类,在FilterOutputStream中的子类有:
    BufferedOutputStream (与BufferedInputStream相反,创建了一个缓冲区进行字节流写操作,先写入缓冲区,缓冲区满了再写入文件或其他输出源)
    DataOutputStream (与DataInputStream相反,将JAVA基础类和String类型直接写入到文件或者其他输出源)
    PrintStream (System类中的in、out和err对象就是PrintStream类的实例,print用法大家应该都会)

3、InputStream和OutputStream
因为InputStream和OutputStream一般是整对出现,所以我们现在逐对类进行讲解,这里先给出个大纲:
    FileInputStream与FileOutputStream 对文件进行读写
    ByteArrayInputStream与ByteArrayOutputStream 对 Byte数组进行读写,一般用于内存数据(虚拟文件或则虚拟镜像)转换或缓存
    DataInputStream与DataOutputStream 与机器无关地读写JAVA和String类,与文件流和Byte数组流等配合使用。
    BufferedInputStream与BufferedOutputStream 创建一个buffer缓冲区进行读写操作与文件流和Byte数组流等配合使用。

3.1、InputStream
InputStream的基本操作:
InputStream in = new InputStream(filePath);int b = in.read(); //读取一个byte字节填充int的低八位, 没有返回-1int len = in.read(byte[] buff);  //将流读取到buff中,并返回读取的byte的长度int len = in.read(byte[] buff, int start, int size); //将流读取到buff中,从哪个位置读,读取多少size,返回已读取的byte的长度in.close(); //关闭流

3.2、OutputStream
OutputStream的基本操作:
OutputStream out = new OutputStream(filePath);out.write(int b); //写入一个byteout.write(byte[] b); //写入一个byte数组out.write(byte[] b, int start, int size); //将b的一部分写入out.flush(); //清理缓存out.close(); //关闭流

3.3、FilterInputStream和FileOutputStream
使用FileInputStream和FileOutputStream对文件进行读写
TestFileInputStream
public class TestFileInputStream {  public static void main(String[] args) throws IOException {  //D:/users/rich/Workspaces/MyEclipse 10/NIO/src/rich/stream/in.txt  //注意这里的相对路径,是要把package都放进去  String file = "src/rich/stream/in.txt";  FileInputStream in = new FileInputStream(file);  int b;  while((b = in.read()) != -1) {   //不用char转换会读出ASCII码的值   System.out.print((char) b);  }  in.close();  System.out.println();  in = new FileInputStream(file);  //available返回剩下还没读的字节数,这里读取文件长度  byte[] buff = new byte[in.available()];  in.read(buff);  //把数据读到buff中  in.close();  //可以关闭流  for(byte c: buff) {   System.out.print((char)c);  } }}

TestFileOutputStream
public class TestFileOutputStream { public static void main(String[] args) throws IOException {  //注意文件路径  String file = "src/rich/stream/out.txt";  FileOutputStream out = new FileOutputStream(file);  String str = "Hi, I am Rich.";  byte[] b = str.getBytes();  out.write(b);  //写入文件  out.flush();//清理缓存  out.close();//关闭流   //将读入流文件写入输出流文件  TestFileOutputStream.fileInputStreamToOutputStream();   }  public static void fileInputStreamToOutputStream() throws IOException {  String inFile = "src/rich/stream/in.txt";  FileInputStream in = new FileInputStream(inFile); //读取文件源  byte[] buff = new byte[in.available()]; //使用一个byte数组  in.read(buff); //把文件内容写入到buff数组中  in.close();//关闭读入流  String outFile = "src/rich/stream/out1.txt";  FileOutputStream out = new FileOutputStream(outFile); //获取写入源  out.write(buff);  //写入文件  out.flush();//清理缓存  out.close(); //关闭写入流 }}

3.4、ByteArrayInputStream和ByteArrayOutputStream

ByteArrayInputStream与ByteArrayOutputStream 对 Byte数组进行读写,一般用于内存数据(虚拟文件或则虚拟镜像)转换或缓存
TestByteArrayStream
public class TestByteArrayStream { public static void main(String[] args) throws IOException {  //这里只是构建一个string放在内存中,一般使用该Stream类是去读取虚拟文件  byte[] buff = new String("I am Rich again").getBytes();  ByteArrayInputStream in = new ByteArrayInputStream(buff);  //这里不做打印操作,直接把read出来的数据放入到ByteArrayOutputStream中  //不需指定数组,内置存有一个byte数组  ByteArrayOutputStream out = new ByteArrayOutputStream();  int b;  while((b = in.read()) != -1) { //读出数据   //写入数据,会把数据写入到out的内置数组中   out.write(Character.toUpperCase(b));  }  in.close(); //关闭输入流  System.out.println(out.toString());  out.close(); //关闭输出流 }}

3.5、DataInputStream和DataOutputStream
 
DataInputStream与DataOutputStream 与机器无关地读写JAVA和String类,与文件流和Byte数组流等配合使用。
TestDataInputStream

public class TestDataInputStream { public static void main(String[] args) throws IOException {  //DataInputStream不能单独使用,这是装饰类  String file = "src/rich/stream/in1.txt";  FileInputStream fileIn = new FileInputStream(file);  DataInputStream dataIn = new DataInputStream(fileIn); //读进输入源   //DataInputStream对象增强了FileInputStream的read方法  //有readInt,看源码其实就是连续读取4个字节,即连续调用四个read方法  int b = dataIn.readInt();  //有readChar,readFloat等等。这里不一一实现。不过感觉并不好用  char c = dataIn.readChar();  System.out.println(b);  System.out.println(c);   dataIn.close(); }}

TestDataOutputStream
public class TestDataOutputStream {  public static void main(String[] args) throws IOException {  String inFile = "src/rich/stream/in.txt";  FileInputStream fileIn = new FileInputStream(inFile); //读出数据源  String outFile = "src/rich/stream/out2.txt";  DataOutputStream dataOut =    new DataOutputStream(new FileOutputStream(outFile)); //增强写入源  int b;  while((b = fileIn.read()) != -1) {   dataOut.writeByte(b); //把in.txt的数据写入到out2.txt  }  fileIn.close();  dataOut.close(); }}

3.6、 BufferedInputStream与BufferedOutputStream
BufferedInputStream与BufferedOutputStream 创建一个buffer缓冲区进行读写操作,与文件流和Byte数组流等配合使用。
TestBufferStream 
public class TestBufferStream { public static void main(String[] args) throws IOException {  String file = "src/rich/stream/in.txt";  //装饰者模式,这样in这个读出源就拥有了一个buffer数组进行缓存,改善性能  BufferedInputStream in = new BufferedInputStream(    new FileInputStream(file));  while(in.available() > 0) {   System.out.print((char)in.read());  }  in.close();  System.out.println();  //可以继续封装,如封装了BufferedInputStream的DataInputStream类,  //拥有了BufferedInputStream的缓冲数组  DataInputStream in1 = new DataInputStream(    new BufferedInputStream(new FileInputStream(file)));  byte[] newBuff = new byte[in1.available()];  in1.read(newBuff);   for(byte c: newBuff) {   System.out.print((char)c);  }  in1.close();   //BufferOutSream的作用相反  byte[] outBuff = "It's an output stream.".getBytes();  String outfile = "src/rich/stream/out3.txt";  BufferedOutputStream out = new BufferedOutputStream(    new FileOutputStream(outfile));  for(byte b: outBuff) {   out.write(b);  }  out.close(); }}

4、Reader和Writer
讲完了字节流,现在是字符流,Reader和Writer类主要用于Unicode编码的字符,而InputStream和OutputStream用于ASCII字符和二进制数据。注意:UTF-8是Unicode的其中一种存储方式。同时要理解,Reader和Writer是对字节流的扩充,底层还是使用字节流进行数据传输。

4.1、Reader
Reader是一个抽象类,用于读取字符流中的数据(文本文件,字符串,基本数据类型等)

InputStreamReader是最常用的类,一般用于对InputStream中的字符进行读取操作,并指定编码格式,不填默认使用系统编码格式;而它的子类FileReader可以直接打开文件进行字符流读写,而FileInputStream则是字节流读入。而BufferedReader是一个装饰类,能够封装Reader,并一次读取一行数据。
TestInputStreamReader
public class TestInputStreamReader { public static void main(String[] args) throws IOException {  String file = "src/rich/reader/in.txt";  FileInputStream in = new FileInputStream(file);  //如果不设置编码格式,会获取程序默认编码格式,跟上面那行是同一个意思// InputStreamReader reader = new InputStreamReader(in);    InputStreamReader reader = new InputStreamReader(in, "GBK");    int b;  while((b = reader.read()) != -1) {   System.out.print((char)b);  }  reader.close();  in.close();  System.out.println();  //字节流不支持中文  in = new FileInputStream(file);  while(in.available() > 0) {   System.out.print((char)in.read());  }  in.close(); }}

TestBufferedReader
public class TestBufferedReader { public static void main(String[] args) throws IOException {  String file = "src/rich/reader/in.txt";  FileReader fileReader = new FileReader(file);  //获取文件Reader  BufferedReader bufferedReader = new BufferedReader(fileReader);  String line;  //使用bufferedReader的readline方法  while((line = bufferedReader.readLine()) != null) {   System.out.println(line);  }  //关闭流  bufferedReader.close();  //可以使用装饰嵌套InputStreamReader指定编码格式  FileInputStream in = new FileInputStream(file);  BufferedReader bufferedReaderForInput = new BufferedReader(    new InputStreamReader(in, "GBK"));   while((line = bufferedReaderForInput.readLine()) != null) {   System.out.println(line);  } }}

4.1、Writer
Writer也是一个抽象类,用于将字符数据写入文件或其他输出源,其中的write方法可以直接写入字符串。

OutputStreamReader是较为常用的类,用于对OutputStream的字符流进行写入,并指定编码格式。相对的,FileWriter是对文件字符流进行写入,FileOutputStream是对字节流进行写入。而BufferedWriter提供与系统文件格式无关的newLine方法,保证另起一行。而不是在字符串后面加"\r\n"。
TestOutputStreamWriter
public class TestOutputStreamWriter { public static void main(String[] args) throws IOException {  String file = "src/rich/writer/out.txt";  FileOutputStream out = new FileOutputStream(file);  OutputStreamWriter writer = new OutputStreamWriter(out);   String str1 = "我是一只小小小小鸟\r\n";  String str2 = "想要飞,却怎么也没不高\r\n";   writer.write(str1);  writer.write(str2);  writer.close(); }}

TestBufferedWriter
public class TestBufferedWriter { public static void main(String[] args) throws IOException {  String file = "src/rich/writer/out1.txt";  FileWriter fileWriter = new FileWriter(file); //写入文件源  BufferedWriter writer = new BufferedWriter(fileWriter);   String str1 = "我是一只小小小小鸟";  String str2 = "想要飞,却怎么也没不高";  String str3 = "I am a Chinese";   writer.write(str1);  //写入字符串  writer.newLine();//加入一个换行符  writer.write(str2);  writer.newLine();  writer.write(str3);  writer.close();   //使用OutputStreamWriter作为输出文件源,并指定编码格式  BufferedWriter fileWriterForOutput = new BufferedWriter(    new OutputStreamWriter(new FileOutputStream(file), "GBK"));  fileWriterForOutput.write(str1);  fileWriterForOutput.newLine();  fileWriterForOutput.write(str2);  fileWriterForOutput.close(); }}

最后给出一个深复制代码,感受一下io的魅力
TestCopyObject
public class TestCopyObject { public static void main(String[] args) throws Exception {  TestCopyObject test = new TestCopyObject();  //User对象是否与另外一个User对象一致  User user = new User("rich", 26);  User user1 = test.deepClone(user); //进行深复制  user.setName("jeff");  //如果是同一引用,user的name应该为jeff  System.out.println(user1.getName());  }   public User deepClone(User user) throws Exception {  //Byte数组输出流,内置一个Byte数组,使用toByteArray方法读出数据  ByteArrayOutputStream out = new ByteArrayOutputStream();  //序列化Byte数组中的数据,即放入ByteArrayOutputStream的对象都是可序列化的  //JAVA基本类型和String类型都已实现 java.io.Serializable  ObjectOutputStream objectOut = new ObjectOutputStream(out);  objectOut.writeObject(user); //写入对象   //toByteArray方法是复制一个byte数组,而不是直接引用  ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());  //读取序列化数据  ObjectInputStream objectIn = new ObjectInputStream(in);  //读取第一个对象(要cast)  return (User)objectIn.readObject(); }}


参考文章:
http://www.cnblogs.com/liqingyuan/archive/2013/06/13/java_01.html



0 0
原创粉丝点击