当前位置:   article > 正文

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为例,水管的每个“水滴”就是具体的数据,如果是字节流,那么一个“水滴”就是一个字节,如果是字符流,那么一个“水滴”就是一个字符。
在这里插入图片描述

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

在这里插入图片描述
2. java的流的图结构:
在这里插入图片描述

三、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));
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

注意:该示例中由于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));
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

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

/**
 * 字节流
 * 读文件内容,节省空间
 * */
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));
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

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

/**
 * 字节流
 *读文件
 * */
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));
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

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();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

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();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

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();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

3.缓存流的使用(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();
		}		
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

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

4.转换流的使用(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();
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

5.对象流的使用(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;
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

字节数组流的使用(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();
		}
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号