JAVA IO API使用详解

 更新时间:2020年09月12日 12:11:27   投稿:zxhpj  
本文通过理论、用法、实例详细说明了JAVA IO的使用,大家参考其中的实例代码实现自己的JAVA IO程序

一.理论准备

流是个抽象的概念,是对输入输出设备的抽象,Java程序中,对于数据的输入/输出操作都是以“流”的方式进行,设备可以是文件、网络、内存等。流具有方向性,至于是输入流还是输出流则是一个相对的概念,一般以程序(小马哥说的是机器)为参考,如果数据的流向是程序至设备,我们成为输出流,反之我们称为输入流,可以将流想象成一个“水流管道”(很多资料都这么讲的),自然就出现了方向的概念。
流把I/O设备内部的具体操作给隐藏起来了。所有InputStream和Reader的派生类都有一个基本的,继承下来的,能读取单个或byte数组的read( )方法。
Java分为字节流(Stream结尾)和字符流(Reader、Write结尾),再分为输入流(InputStream、Reader)和输出流(OutputStream、Write),输入输出相对于内存而言。在读字符的时候用字符流,如文本文件、XML(我想xml明明是字母字符组成的,属于ASCII文件,为何不用stream读取呢?)等。在读二进制文件时候用字节流,如RAR、EXE等不是文本以外的文件(图片)。Buffered开头的流只是加了缓冲区,为了读写提高效率。字符流不能直接输出,需要转换成字节流才能输出(这个确实是刚知道的)!

Java 2 SDK中有三种基本类型的节点:文件(file)、内存(memory)、管道(pipe)。

下面来看郑莉教材上IO章节的那个经典图片。

继承自InputStream/OutputStream的流都是用于向程序中输入/输出数据,且数据的单位都是字节(byte=8bit),如图,深色的为节点流,浅色的为处理流。

继承自Reader/Writer的流都是用于向程序中输入/输出数据,且数据的单位都是字符(2byte=16bit),如图,深色的为节点流,浅色的为处理流。

二.用法分析

Java IO的一般使用原则(部分来自百度文库):

(1) 按数据来源(去向)分类:
是文件: FileInputStream, FileOutputStream, FileReader, FileWriter
是byte[]:ByteArrayInputStream, ByteArrayOutputStream
是Char[]: CharArrayReader, CharArrayWriter
是String: StringBufferInputStream, StringReader, StringWriter
网络数据流:InputStream, OutputStream, Reader, Writer
(2) 按是否格式化输出分:
要格式化输出:PrintStream, PrintWriter
(3) 按是否要缓冲分:
要缓冲:BufferedInputStream, BufferedOutputStream, BufferedReader, BufferedWriter。
(4) 按数据格式分:
二进制格式(只要不能确定是纯文本的): InputStream, OutputStream及其所有带Stream结束的子类
纯文本格式(含纯英文与汉字或其他编码方式);Reader, Writer及其所有带Reader, Writer的子类
(5) 按输入输出分:
输入:Reader, InputStream类型的子类;输出:Writer, OutputStream类型的子类
(6) 特殊需要:
从Stream到Reader,Writer的转换类:InputStreamReader, OutputStreamWriter
对象输入输出:ObjectInputStream, ObjectOutputStream
进程间通信:PipeInputStream, PipeOutputStream, PipeReader, PipeWriter
合并输入:SequenceInputStream
更特殊的需要:PushbackInputStream, PushbackReader, LineNumberInputStream, LineNumberReader
       (7) 决定使用哪个类以及它的构造进程的一般准则如下(不考虑特殊需要):
考虑最原始的数据格式是什么:是否为文本?是输入还是输出?是否需要转换流:InputStreamReader, OutputStreamWriter?数据来源(去向)是什么:文件?内存?网络?是否要缓冲:bufferedReader (特别注明:一定要注意的是readLine()是否有定义,有什么比read, write更特殊的输入或输出方法)是否要格式化输出:print。

三.若干实例

还是寒假时候写的,权当复习了,折叠代码的插件找不到了,先看着吧。

1.System.in

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/*
 * System.in是InputStream static final的,包含了多态,叫同步式或者阻塞式
 * 读取ASCII和二进制文件(图片),而字母就是ASCII字符(个人理解)。
 */
public class TestSystemIn {
 public static void main(String[] args) {
 InputStreamReader isr = new InputStreamReader(System.in);
 BufferedReader br = new BufferedReader(isr);//有readline
 String s = null;
 try {
  s = br.readLine();
  while(s!=null) {
  if(s.equalsIgnoreCase("exit")) {
   break;
  }
  System.out.println(s.toUpperCase());
  s = br.readLine();
  }
  br.close();
 }catch (IOException e) {
  e.printStackTrace();
 }
 }
}

2.buffer

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class TestBuffer {
 public static void main(String[] args) {
 try {
  //查看修改日就可以判断文件是否是新建的了
  BufferedWriter bw = new BufferedWriter(new FileWriter("d:/java.txt"));
  BufferedReader br = new BufferedReader(new FileReader("d:/java.txt"));
  String s = null;
  for(int i=1; i<100; i++) {
  s = String.valueOf(Math.random());
  bw.write(s);
  bw.newLine();//换行
  }
  //刷新该流的缓冲,br没有该方法
  bw.flush();
  while((s=br.readLine())!=null) {
  System.out.println(s);
  }
  bw.close();
  br.close();
 }catch (IOException e) {
  e.printStackTrace();
 }
 }
}

3.FileInputStream

import java.io.*;
public class TestFileInputStream {
 public static void main(String[] args) {
 FileInputStream in = null;
 try {
  in = new FileInputStream("e:/1.txt");
 }catch(FileNotFoundException e) {
  System.out.println("找不到文件");
  System.exit(-1);
 }
 //下面表示找到了文件
 int tag = 0;
 try {
  long num = 0;
  while((tag = in.read())!=-1) {
  //read是字节流,若是有汉字就显示不正常了,使用reader就解决了
  System.out.print((char)tag);
  num++;
  }
  in.close();
  System.out.println();
  System.out.println("共读取了" + num + "字符");
 }catch(IOException e1) {//read和close都会抛出IOException
  System.out.println("文件读取错误");
  System.exit(-1);
 }
 }
}

4.FileOutputStream实现复制功能

import java.io.*;
/*
 * 实现复制功能
 */
public class TestFileOutputStream {
 public static void main(String[] args) {
 int b = 0;
 FileInputStream in = null;
 FileOutputStream out = null;
 try {
  in = new FileInputStream("d:/java.txt");
  //下面的若是不存在的话会自动建立
  out = new FileOutputStream("d:/my_java.txt");
  while((b=in.read())!=-1) {
  out.write(b);
  }
  in.close();
  out.close();
 }catch(FileNotFoundException e) {
  System.out.println("找不到指定文件");
  System.exit(-1);
 }catch(IOException e1) {
  System.out.println("文件复制错误");
  System.exit(-1);
 
 }
 System.out.println("文件已复制"); 
 }
}

5.ObjectOutputStream与Serializable

import java.io.*;
/*
 * transient(透明的),可以用来修饰成员变量,
 * 当进行序列化时不予考虑,修饰int 的话,不管原来的值是多少
 * 输出的就是0
 */
public class TestObjectIO {
 public static void main(String[] args) throws Exception {
 T t = new T();
 t.k = 8;
 FileOutputStream fos = new FileOutputStream("d:/1.txt");
 ObjectOutputStream oos = new ObjectOutputStream(fos);
 oos.writeObject(t);
 oos.flush();
 oos.close();
 
 FileInputStream fis = new FileInputStream("d:/1.txt");
 ObjectInputStream ois = new ObjectInputStream(fis);
 T tRead = (T)ois.readObject();
 System.out.println(tRead.i + " " + tRead.j + " " + tRead.k);
 }
}
class T implements Serializable {
 int i = 10;
 int j = 9;
 double d = 2.3;
 int k = 15;
}

6.转换编码方式

import java.io.*;
/*
 * 中文windows默认GBK编码方式
 * 追加的内容显示为问号,不知道咋回事
 */
public class TestTransForm {
 public static void main(String[] args) {
 try {
  OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d:/java.txt"));
  osw.write("你好123");//可以直接写入字符串,包括中文,因为外边的是字符流
  System.out.println("编码方式:" + osw.getEncoding());//ISO8859_1是西欧语言,又叫latin-1,此时未考虑东方人,国标(ISO)为Unicode
  osw.close();
  osw = new OutputStreamWriter(new FileOutputStream("d:/java.txt",true),"ISO8859_1");//true表示追加
  osw.write("这是追加的内容");
  System.out.println("编码方式:" + osw.getEncoding());
  osw.close();
 }catch(IOException e) {
  e.printStackTrace();
 }
 }
}

7.输出重定向

import java.io.*;
/*
 * Print流属于输出流,提供了重载的方法很多,
 * PrintWriter和PrintStream不会抛异常,用户通过检测错误状态获取信息,
 * 包含自动flush功能,有什么用呢,在jsp里也要输出一些东西,
 * 但不必每次抛异常。
 */
public class TestPrintStream {
 public static void main(String[] args) {
 PrintStream ps = null;
 try {
  FileOutputStream fos = new FileOutputStream("d:/java.txt");
  ps = new PrintStream(fos);
  
 }catch (IOException e) {
  e.printStackTrace();
 }
 if(ps!=null) {
  System.setOut(ps);//输出重定向
 }
 int ln = 0;
 for(char c=0; c<65535; c++) {
  System.out.print(c + " ");
  if(ln++>100) {
  System.out.println();
  ln = 0; 
  }
 }
 }
}

8.DataStream

import java.io.*;
public class TestDataStream {
 public static void main(String[] args) {
 //先在内存里分配一个字节数组,再有一个 OutputStream,再加上一个数据流
 ByteArrayOutputStream baos = new ByteArrayOutputStream();
 DataOutputStream dos = new DataOutputStream(baos);
 try {//写出读入
  dos.writeDouble(Math.random());
  dos.writeBoolean(true);
  ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
  System.out.println(bais.available());//共几个字节可用
  DataInputStream dis = new DataInputStream(bais);
  ////先写的先读(队列),下面这两个输出不可以调换,否则就先输出了double里的一个字节
  System.out.println(dis.readDouble());
  System.out.println(dis.readBoolean());
  dos.close();
  dis.close();
 }catch (IOException e) {
  e.printStackTrace(); 
 }
 }
}

四.小问题

为什么Writer/Reader不继承自Stream呢?字符最终也要转换成二进制呀。Writer/Readre继承OutputStream/InputStream,这样的继承层次不是更好,为什么要单独做一个呢,而且Stream也有些子类能够实现字符串的读写。大神回答:单一职责。太牵强了。

相关文章

  • Java使用黑盒方式模拟实现内网穿透

    Java使用黑盒方式模拟实现内网穿透

    这篇文章主要介绍了Java使用黑盒方式模拟实现内网穿透,内网穿透,也即 NAT 穿透,进行 NAT 穿透是为了使具有某一个特定源 IP 地址和源端口号的数据包不被 NAT 设备屏蔽而正确路由到内网主机,需要的朋友可以参考下
    2023-05-05
  • Spring Cloud Config RSA简介及使用RSA加密配置文件的方法

    Spring Cloud Config RSA简介及使用RSA加密配置文件的方法

    Spring Cloud 为开发人员提供了一系列的工具来快速构建分布式系统的通用模型 。本文重点给大家介绍Spring Cloud Config RSA简介及使用RSA加密配置文件的方法,感兴趣的朋友跟随脚步之家小编一起学习吧
    2018-05-05
  • Java常用集合之Set和Map的用法详解

    Java常用集合之Set和Map的用法详解

    这篇文章将通过一些示例为大家详细介绍一下Java常用集合中Set和Map的用法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2022-07-07
  • Java实现游戏飞机大战-III的示例代码

    Java实现游戏飞机大战-III的示例代码

    这篇文章主要为大家介绍了如何利用Java实现经典的游戏之飞机大战,文中采用了swing技术进行了界面化处理,感兴趣的小伙伴可以动手试一试
    2022-02-02
  • SpringBoot中的ApplicationListener事件监听器使用详解

    SpringBoot中的ApplicationListener事件监听器使用详解

    这篇文章主要介绍了SpringBoot中的ApplicationListener事件监听器使用详解,ApplicationListener是应用程序的事件监听器,继承自java.util.EventListener标准接口,采用观察者设计模式,需要的朋友可以参考下
    2023-11-11
  • Prometheus pushgateway的使用详解

    Prometheus pushgateway的使用详解

    为了防止 pushgateway 重启或意外挂掉,导致数据丢失,我们可以通过 -persistence.file 和 -persistence.interval 参数将数据持久化下来,接下来通过本文给大家介绍下Prometheus pushgateway的使用,感兴趣的朋友一起看看吧
    2021-11-11
  • Java调用python代码的五种方式总结

    Java调用python代码的五种方式总结

    这篇文章主要给大家介绍了关于Java调用python代码的五种方式,在Java中调用Python函数的方法有很多种,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2023-09-09
  • java的Jackson将json字符串转换成泛型List

    java的Jackson将json字符串转换成泛型List

    这篇文章主要介绍了java的Jackson将json字符串转换成泛型List ,这里整理了详细的代码,有需要的小伙伴可以参考下。
    2017-02-02
  • xxl-job 带参数执行和高可用部署方法

    xxl-job 带参数执行和高可用部署方法

    这篇文章主要介绍了xxl-job 带参数执行和高可用部署,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-04-04
  • HashMap线程不安全问题解析

    HashMap线程不安全问题解析

    这篇文章主要介绍了HashMap线程不安全问题解析,HashMap的线程不安全体现在会造成死循环、数据丢失、数据覆盖等问题,其中死循环和数据丢失是在JDK1.7中出现的问题,在JDK1.8中已经得到解决,但是1.8中仍会有数据覆盖这样的问题,需要的朋友可以参考下
    2023-11-11

最新评论