欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JAVA IO API使用详解

程序员文章站 2024-02-14 10:15:46
一.理论准备流是个抽象的概念,是对输入输出设备的抽象,java程序中,对于数据的输入/输出操作都是以“流”的方式进行,设备可以是文件、网络、内存等。流具有方向性,至于是输入...

一.理论准备
流是个抽象的概念,是对输入输出设备的抽象,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),如图,深色的为节点流,浅色的为处理流。
JAVA IO API使用详解
继承自reader/writer的流都是用于向程序中输入/输出数据,且数据的单位都是字符(2byte=16bit),如图,深色的为节点流,浅色的为处理流。
JAVA IO API使用详解

二.用法分析
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也有些子类能够实现字符串的读写。大神回答:单一职责。太牵强了。