JAVA IO API使用详解

一.理论准备
流是个抽象的概念,是对输入输出设备的抽象,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.输出重定向
[code]
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也有些子类能够实现字符串的读写。大神回答:单一职责。太牵强了。

(0)

相关推荐

  • Java8新日期时间API的20个使用示例

    除了lambda表达式,stream以及几个小的改进之外,Java 8还引入了一套全新的时间日期API,在本篇教程中我们将通过几个简单的任务示例来学习如何使用Java 8的这套API.Java对日期,日历及时间的处理一直以来都饱受诟病,尤其是它决定将java.util.Date定义为可修改的以及将SimpleDateFormat实现成非线程安全的.看来Java已经意识到需要为时间及日期功能提供更好的支持了,这对已经习惯使用Joda时间日期库的社区而言也是件好事.关于这个新的时间日期库的最大的优点

  • java调用百度定位api服务获取地理位置示例

    复制代码 代码如下: package test; import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.Reader;import java.net.URL;import java.nio.charset.Charset; import org.json.JSONException;imp

  • 详解Java的JDBC API中事务的提交和回滚

    如果JDBC连接是在自动提交模式下,它在默认情况下,那么每个SQL语句都是在其完成时提交到数据库. 这可能是对简单的应用程序,但有三个原因,你可能想关闭自动提交和管理自己的事务: 为了提高性能 为了保持业务流程的完整性 使用分布式事务 若要控制事务,以及何时更改应用到数据库.它把单个SQL语句或一组SQL语句作为一个逻辑单元,而且如果任何语句失败,整个事务失败. 若要启用,而不是JDBC驱动程序默认使用auto-commit模式手动事务支持,使用Connection对象的的setAutoComm

  • java调用中国天气网api获得天气预报信息的方法

    本文实例讲述了java调用中国天气网api获得天气预报信息的方法.分享给大家供大家参考.具体实现方法如下: //以冰城哈尔滨为例通过中国天气api调用天气信息 private String getWeatherInfo2(){ StringBuilder info = new StringBuilder(); try { DefaultHttpClient httpclient = new DefaultHttpClient(); HttpGet httget = new HttpGet("ht

  • java使用淘宝API读写json实现手机归属地查询功能代码

    一般查询手机归属地内容应该很好用json格式保存,在网上找到了淘宝的归属地API,并下了处理json相关的jar包,做了这个手机归属地查询功能 复制代码 代码如下: package com.think.java; import java.io.BufferedReader;import java.io.InputStream;import java.io.InputStreamReader;import java.net.MalformedURLException;import java.net

  • 用Java实现全国天气预报的api接口调用示例

    step1:选择本文所示例的接口"全国天气预报接口" 聚合数据url:http://www.juhe.cn/docs/api/id/39/aid/87 step2:每个接口都需要传入一个参数key,相当于用户的令牌,所以第一步你需要申请一个key. step3:学过java的同学们都知道,当我们对一个类或者方法不明白其意图和思想时,我们可以去查看文档,这里也不例外,而且对于英文不是特别好的同学来说很幸运的是,聚合网站上的文档都是中文版本的,比起阅读java源码里的英文文档应该轻松很多.

  • Java通过JsApi方式实现微信支付

    要使用JsApi进行微信支付,首先要从微信获得一个prepay_id,然后通过调用微信的jsapi完成支付,JS API的返回结果get_brand_wcpay_request:ok仅在用户成功完成支付时返回.由于前端交互复杂,get_brand_wcpay_request:cancel或者get_brand_wcpay_request:fail可以统一处理为用户遇到错误或者主动放弃,不必细化区分. 示例代码如下: function onBridgeReady(){ WeixinJSBridge

  • 5个Java API使用技巧

    本文介绍了一些关于Java API安全和性能方面的简单易用的技巧,其中包括保证API Key安全和开发Web Service方面中在框架方面选择的一些建议. 程序员都喜欢使用API!例如为app应用构建API或作为微服务架构体系的一部分.当然,使用API的前提是能让你的工作变得更轻松.为了简化开发和提高工作效率所作出的努力,有时也意味着需要寻找新的类库或者过程(或者减少过程).对于很多开发团队来说,对于其APP和API进行管理认证和访问控制要耗费很多的时间,因此我们需想分享一些技巧,它们能节约你

  • android monkey自动化测试改为java调用monkeyrunner Api

    众所周知,一般情况下我们使用android中的monkeyrunner进行自动化测试时,使用的是python语言来写测试脚本.不过,最近发现可以用java调用monkeyrunner Api,用java语言写测试脚本. 于是,就简单研究了一下.这里做一些总结.希望有对在研究的午饭可以有所用处. 开始时,搜素到一些零碎的教程,说使用java调用monkeyrunner时,需要导入android sdk  tools路径下的lib里面的4个包:ddmlib.jar,guavalib.jar,monk

  • Java中的Calendar日历API用法完全解析

    第一部分 Calendar介绍 Calendar 定义: public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar> {} Calendar 可以看作是一个抽象类. 它的实现,采用了设计模式中的工厂方法.表现在:当我们获取Calendar实例时,Calendar会根据传入的参数来返回相应的Calendar对象.获取Calendar实例,有以下两种方式: (1) 当我们通过 Cal

随机推荐