Java io详解

流的本质是数据传输,根据数据传输特点抽象为不同的流对象,方便直观地进行数据操作。

根据处理的数据类型分为字节流和字符流。
字节流以字节(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的低八位, 没有返回-1
int 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); //写入一个byte
out.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();
 }

}


参考文章:



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值