Java io流 详解

简介: Java io流 详解

前言


"IO流"(Input/Output stream)指的是Java中用于处理输入输出(I/O)数据的机制。在Java中,所有的输入和输出都被抽象为“流”对象,并通过输入流读取数据、输出流写入数据。

Java的I/O包提供了丰富的类和方法来支持不同类型的流,输入流和输出流之间可以自由地进行转换。它们分别主要包括字节流和字符流两种类型。其中,字节流是操作二进制数据的流,可以处理任何类型的数据,常见的例如InputStream和OutputStream;字符流则是处理字符数据的流,其主要使用Reader和Writer接口。

Java中的IO流可以对文件、网络套接字等的数据进行读写操作,这些操作涉及到打开、关闭、查找、修改和删除文件、创建及维护网络连接等等一系列活动。因此,掌握Java中IO流的知识,有助于我们实现更加高效准确地操作文件、网络数据等各种实用应用。


一、IO流的分类


可以从三个不同的维度进行分类:


• 1、按照流的方向(输出输入都是站在程序所在内存的角度划分的)

• 输入流:只能从中读取数据【主要由InputStream和Reader作为基类】


• 输出流:只能向其写入数据【主要由outputStream和Writer作为基类】


• 2、按照流的操作颗粒度划分


• 字节流:以字节为单元,可操作任何数据【主要由InputStream和outPutStream作为基类】


• 字符流:以字符为单元,只能操作纯字符数据,比较方便【主要由Reader和Writer作为基类】


• 3、按照流的角色划分


• 节点流:可以从/向一个特定的IO设备(如磁盘,网络)读/写数据的流,也叫【低级流,主要由】


• 处理流:用于对一个已存在的流进行连接和封装,通过封装后的流来实现数据的读/写功能,也叫【高级流】


二、流的原理及流的数量


• 1、流的原理解析

流其实我们可以想象成一个“水管”,源端和目的端就是两个“水桶”,数据是通过这个“水管”进行流动传输的,以InputStream和Reader为例,水管的每个“水滴”就是具体的数据,如果是字节流,那么一个“水滴”就是一个字节,如果是字符流,那么一个“水滴”就是一个字符。

df1a237873df4a43ab6a9d51b9933be9.jpg

当创建一个流对象的时候,如fis=new FileInputStream(“…\xx\xx.txt”),记录指针来表示当前正准备从哪个“水滴”开始读取,每当程序从InputStream或者Reader里面取出一个或者多个“水滴”后,记录指针自定向后移动;除此之外,InputStream和Reader里面都提供了一些方法来控制记录指针的移动。

f9a3ccbfd2db456ab7614e5982f910f5.jpg

2. java的流的图结构:

6714c842898e411bae9ce70ebcfcde46.png


三、Java IO流对象


1. 输入字节流InputStream


定义和结构说明:

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

ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三种基本的介质流,它们分别从Byte 数组、StringBuffer、和本地文件中读取数据。PipedInputStream 是从与其它线程共用的管道中读取数据,与Piped 相关的知识后续单独介绍。

ObjectInputStream 和所有FilterInputStream的子类都是装饰流(装饰器模式的主角)。

意思是FileInputStream类可以通过一个String路径名创建一个对象,FileInputStream(String name)。而DataInputStream必须装饰一个类才能返回一个对象,DataInputStream(InputStream in)。


【案例 】读取文件内容

/**
 * 字节流
 * 读文件内容
 * */
import java.io.*;
class hello{
   public static void main(String[] args) throws IOException {
       String fileName="D:"+File.separator+"hello.txt";
       File f=new File(fileName);
       InputStream in=new FileInputStream(f);
       byte[] b=new byte[1024];
       in.read(b);
       in.close();
       System.out.println(new String(b));
    }
}


注意:该示例中由于b字节数组长度为1024,如果文件较小,则会有大量填充空格。我们可以利用in.read(b);的返回值来设计程序,如下案例:

/**
 * 字节流
 * 读文件内容
 * */
import java.io.*;
class hello{
   public static void main(String[] args) throws IOException {
       String fileName="D:"+File.separator+"hello.txt";
       File f=new File(fileName);
       InputStream in=new FileInputStream(f);
       byte[] b=new byte[1024];
       int len=in.read(b);
       in.close();
       System.out.println("读入长度为:"+len);
       System.out.println(new String(b,0,len));
    }
}


注意:观察上面的例子可以看出,我们预先申请了一个指定大小的空间,但是有时候这个空间可能太小,有时候可能太大,我们需要准确的大小,这样节省空间,那么我们可以这样做:

/**
 * 字节流
 * 读文件内容,节省空间
 * */
import java.io.*;
class hello{
   public static void main(String[] args) throws IOException {
       String fileName="D:"+File.separator+"hello.txt";
       File f=new File(fileName);
       InputStream in=new FileInputStream(f);
       byte[] b=new byte[(int)f.length()];
       in.read(b);
       System.out.println("文件长度为:"+f.length());
       in.close();
       System.out.println(new String(b));
    }
}


注意:有时候我们不知道文件有多大,这种情况下,我们需要判断是否独到文件的末尾。

/**
 * 字节流
 *读文件
 * */
import java.io.*;
class hello{
   public static void main(String[] args) throws IOException {
       String fileName="D:"+File.separator+"hello.txt";
       File f=new File(fileName);
       InputStream in=new FileInputStream(f);
       byte[] b=new byte[1024];
       int count =0;
       int temp=0;
       while((temp=in.read())!=(-1)){
           b[count++]=(byte)temp;
       }
       in.close();
       System.out.println(new String(b));
    }
}


2. 输出字节流OutputStream


定义和结构说明:


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


ByteArrayOutputStream、FileOutputStream是两种基本的介质流,它们分别向Byte 数组、和本地文件中写入数据。PipedOutputStream 是向与其它线程共用的管道中写入数据,


ObjectOutputStream 和所有FilterOutputStream的子类都是装饰流。具体例子跟InputStream是对应的。


1.向文件中写入字符串

/**
 * 字节流
 * 向文件中写入字符串
 * */
import java.io.*;
class hello{
   public static void main(String[] args) throws IOException {
       String fileName="D:"+File.separator+"hello.txt";
       File f=new File(fileName);
       OutputStream out =new FileOutputStream(f);
       String str="Hello World";
       byte[] b=str.getBytes();
       out.write(b);
       out.close();
    }
}


2.向文件中追加新内容

/**
 * 字节流
 * 向文件中追加新内容:
 * */
import java.io.*;
class hello{
   public static void main(String[] args) throws IOException {
       String fileName="D:"+File.separator+"hello.txt";
       File f=new File(fileName);
       OutputStream out =new FileOutputStream(f,true);//true表示追加模式,否则为覆盖
       String str="Rollen";
       //String str="\r\nRollen"; 可以换行
       byte[] b=str.getBytes();
       for (int i = 0; i < b.length; i++) {
           out.write(b[i]);
       }
       out.close();
    }
}


3. 复制文件

/**
 * 文件的复制
 * */
import java.io.*;
class hello{
   public static void main(String[] args) throws IOException {
       if(args.length!=2){
           System.out.println("命令行参数输入有误,请检查");
           System.exit(1);
       }
       File file1=new File(args[0]);
       File file2=new File(args[1]);
       if(!file1.exists()){
           System.out.println("被复制的文件不存在");
           System.exit(1);
       }
       InputStream input=new FileInputStream(file1);
       OutputStream output=new FileOutputStream(file2);
       if((input!=null)&&(output!=null)){
           int temp=0;
           while((temp=input.read())!=(-1)){
                output.write(temp);
           }
       }
       input.close();
       output.close();
    }
}


4.缓存流的使用(BufferedInputStream/BufferedOutputStream,BufferedReader/BufferedWriter)

import java.io.*;
public class TestBufferStream {
  public static void main (String[] args) throws IOException{
    BufferedInputStream bis=null;
    BufferedOutputStream bos=null;
    try {
      FileInputStream fis = new FileInputStream("C:\\Users\\41639\\Desktop\\java\\FileText\\src\\TestFileImportStream.java");
      FileOutputStream fos = new FileOutputStream("C:\\Users\\41639\\Desktop\\java\\temp\\out2.java");
      bis = new BufferedInputStream(fis);
      bos = new BufferedOutputStream(fos);
      byte[] b = new byte[1024];
      int off=0;
      while ((off=bis.read(b))>0) {
        bos.write(b,0,off);
      }
      bis.close();
      bos.close();
    }catch (IOException e) {
      e.printStackTrace();
    }finally {
      bis.close();
      bos.close();
    }   
  }
}

他们最基本的其实也是FileInputStream和FileOutputStream,在这个“流”的基础上,又加了缓存的功能流BufferedInputStream和BufferedOutputStream。


5.转换流的使用(InputStreamReader/OutputStreamWriter)

字面意思理解,转化流就是用来转化的,那么到底是什么转什么呢?我们可以通过以下的例子来熟悉。读取键盘输入的每一行内容,并写入到文本中,直到遇到over行结束输入

public static void main(String[] args) throws IOException {
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    BufferedWriter bw = new BufferedWriter(new FileWriter("C:\\Users\\41639\\Desktop\\java\\temp\\test1031.txt"));
    String line =null;
    while ((line=br.readLine())!=null) {
      if ("over".contentEquals(line)) {
        break;
      }
      bw.write(line);
      bw.newLine();
      bw.flush();
    }
    bw.close();
    br.close();
  }


6.对象流的使用(FileInputStream/ObjectOutputStream)

import java.io.*;
public class ObjectStreamTest {
  public static void main(String[] args) throws Exception{
    try {
      Person P=new Person("Jeccica",26);
      FileOutputStream fos=new FileOutputStream("C:\\Users\\admin\\Desktop\\Java\\temp\\22.txt");
      ObjectOutputStream oos=new ObjectOutputStream(fos);
      oos.writeObject(P);
      oos.flush();
      oos.close();
    }catch(FileNotFoundException e) {
      e.printStackTrace();
    }catch(IOException e) {
      e.printStackTrace();
    }     
    FileInputStream fis=new FileInputStream("C:\\Users\\admin\\Desktop\\Java\\temp\\22.txt");
    ObjectInputStream ois=new ObjectInputStream(fis);
    Person P2=(Person)ois.readObject();
    System.out.println(P2.name+"的年龄为"+P2.age);
  }
}
class Person implements Serializable{
  String name=null;
  int age=0;
  Person(String _name,int _age){
    name=_name;
    age=_age;
  }
}


字节数组流的使用(ByteArrayInputStream/ByteArrayOutputStream)【通常结合数据流DataInputStream/DataOutputStream】

public static void main(String[] args) {
    ByteArrayOutputStream baos=new ByteArrayOutputStream();//创建字节数组流,同时会在内存里面创建数组
    DataOutputStream dos=new DataOutputStream(baos);//对字节数组流外封装成数据处理流
    try {
      dos.writeDouble(Math.random());//利用数据流里面的写入方法,写一个Double类型的随机数据
      dos.writeBoolean(true);
      ByteArrayInputStream bias=new ByteArrayInputStream(baos.toByteArray());//toByteArray()方法是创建一个新分配的字节数组。数组的大小和当前输出流的大小。这里指的是baos这个字节数组
      System.out.println(bias.available());
      DataInputStream dis=new DataInputStream(bias);
      System.out.println(dis.readDouble());
      System.out.println(dis.readBoolean());    
      dos.close();
      dis.close();
    }catch (IOException e) {
      e.printStackTrace();
    }
  }


目录
相关文章
|
2天前
|
Java
【Java基础】输入输出流(IO流)
Java基础、输入输出流、IO流、流的概念、输入输出流的类层次结构图、使用 InputStream 和 OutputStream流类、使用 Reader 和 Writer 流类
14 1
|
2天前
|
存储 缓存 Java
Java基础17-读懂Java IO流和常见面试题(二)
Java基础17-读懂Java IO流和常见面试题(二)
15 0
|
2天前
|
存储 Java Unix
Java基础17-读懂Java IO流和常见面试题(一)
Java基础16-读懂Java IO流和常见面试题(一)
15 0
|
7天前
|
存储 算法 NoSQL
JAVA—IO流知识点总结
JAVA—IO流知识点总结
|
10天前
|
Java 应用服务中间件
已解决:An error occurred at line: 1 in the generated java file The type java.io.ObjectInputStream canno
已解决:An error occurred at line: 1 in the generated java file The type java.io.ObjectInputStream canno
|
11天前
|
Java
io读两个文件,生成list 排重后写本地文件(Java)
io读两个文件,生成list 排重后写本地文件(Java)
|
11天前
|
Java Windows
文件操作和IO(2):Java中操作文件
文件操作和IO(2):Java中操作文件
7 0
|
15天前
|
存储 Java API
Java语言IO(输入/输出)编程技术深度解析
Java语言IO(输入/输出)编程技术深度解析
248 1
|
16天前
|
存储 监控 Java
Java nio非阻塞io
Java nio非阻塞io
|
19天前
|
存储 Java API
Java IO流
Java IO流
28 2