字节流与字符流

本章目标
掌握流的概念
掌握字节流与字符流的作用
掌握文件的标准操作步骤
掌握字节与字符操作的区别

 


在程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据的时候要使用输入流读取数据,而当程序需要将一些数据保存起来的时候,就要使用输出流完成 。

字节流与字符流
 

字节流与字符流
在java.io包中操作文件内容的主要有两大类:字节流、字符流,两类都分为输入和输出操作。在字节流中输出数据主要是使用OutputStream完成,输入使的是InputStream,在字符流中输出主要是使用Writer类完成,输入主要是使用Reader类完成。

 

操作流程
在JAVA中IO操作也是有相应步骤的,以文件操作为例,主要的操作流程如下:
——A、  使用File类打开一个文件
——B、  通过字节流或字符流的子类,指定输出的位置
——C、  进行读/写操作
——D、  关闭输入/输出

字节流
字节流主要是操作byte类型数据,以byte数组为准,主要操作类就是OutputStream、InputStream。
字节输出流:OutputStream
字节输入流:InputStream

 

OutputStream类
OutputStream是整个io包中字节输出流的最大父类,此类的定义如下:
——public abstract class OutputStream extends Object implements Closeable, Flushable
从以上的定义中可以发现,此类是一个抽象类,如果要想使用此类的话,则首先必须通过子类实例化对象,那么如果现在要操作的是一个文件,则可以使用:FileOutputStream类。通过向上转型之后,可以为OutputStream实例化

 

OutputStream类的常用方法
字节流与字符流
 

 向文件中写入字符串

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class OutputStreamDemo01{
	public static void main(String[] args) throws Exception {//异常抛出,不处理
		//第 1 步:使用 File 类找到一个文件
		File f = new File("d:"+File.separator+"test.txt");//声明 File 对象
		//第 2 步:通过子类实例化父类对象
		OutputStream out  = null;//准备好一个 输出流对象
		out = new FileOutputStream(f);//通过对象多态性,进行实例化
		//第 3 步:进行写操作
		String str = "Hello World!!!";//准备一个字符串
		byte b[] = str.getBytes();//只好输出 byte 数组,所以将字符串变为 byte 数组
		out.write(b);//将内容输出,保存文件
		//第 4 步关闭输出流
		out.close();//关闭输出流
	}
/* 结果:向文件中写入字符串
 * Hello World!!!
 * */
}

 

 

使用write(int t)的方式写入文件内容

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class OutputStreamDemo02{
	public static void main(String[] args) throws Exception {//异常抛出,不处理
		//第 1 步:使用 File 类找到一个文件
		File f = new File("d:"+File.separator+"test.txt");//声明 File 对象
		//第 2 步:通过子类实例化父类对象
		OutputStream out  = null;//准备好一个 输出流对象
		out = new FileOutputStream(f);//通过对象多态性,进行实例化
		//第 3 步:进行写操作
		String str = "Hello World!!!";//准备一个字符串
		byte b[] = str.getBytes();//只好输出 byte 数组,所以将字符串变为 byte 数组
		for(int i=0; i<b.length; i++){
			out.write(b[i]);//将内容输出
		}
		//第 4 步关闭输出流
		out.close();//关闭输出流
	}
/* 结果:向文件中写入字符串
 * Hello World!!!
 * */
}

 

 

 追加新内容
之前的所有操作中,如果重新执行程序,则肯定会覆盖文件中的已有内容,那么此时可以通过FielOutputStream向文件中追加内容,FileOutputStream的另外一个构造方法:
——public FileOutputStream(File file,boolean append) throws FileNotFoundException
在构造方法中,如果将append的值设置为true,则表示在文件的末尾追加内容。

 

修改之前的程序,追加文件内容

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class OutputStreamDemo03{
	public static void main(String[] args) throws Exception {//异常抛出,不处理
		//第 1 步:使用 File 类找到一个文件
		File f = new File("d:"+File.separator+"test.txt");//声明 File 对象
		//第 2 步:通过子类实例化父类对象
		OutputStream out  = null;//准备好一个输出的对象
		out = new FileOutputStream(f,true);//此处表示在文件末尾追加内容
		//第 3 步:进行写操作
		String str = "Hello World!!!";//准备一个字符串
		byte b[] = str.getBytes();//只好输出 byte 数组,所以将字符串变为 byte 数组
		for(int i=0; i<b.length; i++){
			out.write(b[i]);//将内容输出
		}
		//第 4 步关闭输出流
		out.close();//关闭输出流
	}
/* 结果:修改之前的程序,追加文件内容
 * Hello World!!!Hello World!!!Hello World!!!
 * */
}

 

 

字节输入流:InputStream
既然程序可以向文件中写入内容,则就可以通过InputStream从文件中把内容读取进来,首先来看InputStream类的定义:
——public abstract class InputStream extends Object implements Closeable
与OutputStream类一样,InputStream本身也是一个抽象类,必须依靠其子类,如果现在是从文件中读取,子类肯定是FileInputStream。
——观察FileInputStream类的构造方法:
————public FileInputStream(File file) throws FileNotFoundException

 

InputStream类的常用方法
字节流与字符流
 

 从文件中读取内容

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class InputStreamDemo01{
	public static void main(String[] args) throws Exception {//异常抛出,不处理
		//第 1 步:使用 File 类找到一个文件
		File f = new File("d:"+File.separator+"test.txt");//声明 File 对象
		//第 2 步:通过子类实例化父类对象
		InputStream input  = null;//准备好一个 输入流的对象
		input = new FileInputStream(f);//通过对象多态性,进行实例化
		//第 3 步:进行读操作
		byte b[] = new byte[1024];//所有的内容读到此数组中
		input.read(b);//把内容取出,内容读到 byte 数组中
		//第 4 步关闭输入流
		input.close();//关闭输入流
		System.out.println("内容为:"+new String(b));//把 byte 数组变为字符串输出
	}
/* 结果:从文件中读取内容
 * 内容为:Hello World!!!I am chaoyi!!!
 * 下面都为空格
 * 
 * 
 * 
 * */
}

 

 

输出数组中指定位置的内容

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class InputStreamDemo02{
	public static void main(String[] args) throws Exception {//异常抛出,不处理
		//第 1 步:使用 File 类找到一个文件
		File f = new File("d:"+File.separator+"test.txt");//声明 File 对象
		//第 2 步:通过子类实例化父类对象
		InputStream input  = null;//准备好一个 输入流的对象
		input = new FileInputStream(f);//通过对象多态性,进行实例化
		//第 3 步:进行读操作
		byte b[] = new byte[1024];//所有的内容读到此数组中
		int len = input.read(b);//将内容读出,得到返回值的长度
		//第 4 步关闭输入流
		input.close();//关闭输入流
		System.out.println("读入数据的长度:"+len);
		System.out.println("内容为:"+new String(b,0,len));//把 byte 数组变为字符串输出
	}
/* 结果:从文件中读取内容
 * 读入数据的长度:28
 * 内容为:Hello World!!!I am chaoyi!!!
 * */
}

 

 

开辟指定大小的byte数组

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class InputStreamDemo03{
	public static void main(String[] args) throws Exception {//异常抛出,不处理
		//第 1 步:使用 File 类找到一个文件
		File f = new File("d:"+File.separator+"test.txt");//声明 File 对象
		//第 2 步:通过子类实例化父类对象
		InputStream input  = null;//准备好一个 输入流的对象
		input = new FileInputStream(f);//通过对象多态性,进行实例化
		//第 3 步:进行读操作
		byte b[] = new byte[(int)f.length()];//所有的内容读到此数组中,数组大小由文件决定
		input.read(b);//将内容读出
		//第 4 步关闭输入流
		input.close();//关闭输入流
		System.out.println("内容为:"+new String(b));//把 byte 数组变为字符串输出
	}
/* 结果:从文件中读取内容
 * 内容为:Hello World!!!I am chaoyi!!!
 * */
}

 

 

使用read()通过循环读取

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class InputStreamDemo04{
	public static void main(String[] args) throws Exception {//异常抛出,不处理
		//第 1 步:使用 File 类找到一个文件
		File f = new File("d:"+File.separator+"test.txt");//声明 File 对象
		//第 2 步:通过子类实例化父类对象
		InputStream input  = null;//准备好一个 输入流的对象
		input = new FileInputStream(f);//通过对象多态性,进行实例化
		//第 3 步:进行读操作
		byte b[] = new byte[(int)f.length()];//所有的内容读到此数组中,数组大小由文件决定
		for(int i=0; i<b.length; i++){
			b[i] = (byte)input.read();//将内容读出
		}
		//第 4 步关闭输入流
		input.close();//关闭输入流
		System.out.println("内容为:"+new String(b));//把 byte 数组变为字符串输出
	}
/* 结果:从文件中读取内容
 * 内容为:Hello World!!!I am chaoyi!!!
 * */
}

 

 

另一种方式的读取

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class InputStreamDemo05{
	public static void main(String[] args) throws Exception {//异常抛出,不处理
		//第 1 步:使用 File 类找到一个文件
		File f = new File("d:"+File.separator+"test.txt");//声明 File 对象
		//第 2 步:通过子类实例化父类对象
		InputStream input  = null;//准备好一个 输入流的对象
		input = new FileInputStream(f);//通过对象多态性,进行实例化
		//第 3 步:进行读操作
		int len = 0;//用于记录读取的数据个数
		byte b[] = new byte[1024];//所有的内容读到此数组中
		int temp = 0;//接收读取的每一个内容
		while((temp = input.read()) != -1){
			//将每次的读取内容给 temp 变量,如果 temp 的值不是 -1,则表示文件没有读完
			b[len] = (byte)temp;
			len++;
		}
		//第 4 步关闭输入流
		input.close();//关闭输入流
		System.out.println("内容为:"+new String(b,0,len));
	}
/* 结果:
 * 内容为:Hello World!!!I am chaoyi!!!
 * */
}

 

 

字符流
在程序中一个字符等于2个字节,那么JAVA提供了Reader、Writer两个专门操作字符流的类。
——字符输出流:Writer
——字符输入流:Reader

 

字符输出流:Writer
Writer本身是一个字符流的输出类,此类的定义如下:
——public abstract class Writer extends Object implements Appendable, Closeable, Flushable
此类本身也是一个抽象类,如果要想使用此类,则肯定要使用其子类,此时如果是向文件中写入内容,所以应该使用FileWriter的子类。
——FileWriter类的构造方法定义如下:
————public FileWriter(File file) throws IOException

 

Writer类的常用方法
字节流与字符流
 

向文件中写入数据

import java.io.File;
import java.io.FileWriter;
import java.io.Writer;
public class WriteDemo01{
	public static void main(String[] args) throws Exception {//异常抛出,不处理
		//第 1 步:使用 File 类找到一个文件
		File f = new File("d:"+File.separator+"test.txt");//声明 File 对象
		//第 2 步:通过子类实例化父类对象
		Writer out = null;//准备好一个输出流的对象
		out = new FileWriter(f);//通过对象多态性,进行实例化
		//第 3 步:进行写操作
		String str = "Hello World!!!";//准备一个字符串
		out.write(str);//将内容输出
		//第 4 步关闭输出流
		out.close();//关闭输出流
	}
/* 结果:向文件中写入数据
 * Hello World!!!
 * */
}

 

 

使用FileWriter追加文件的内容
在使用字符流操作的时候,也可以实现文件的追加功能,直接使用FileWriter类中的以下构造即可实现追加:
——public FileWriter(File file,boolean append) throws IOException
————将append的值设置成true,就表示追加。

 

追加文件内容

import java.io.File;
import java.io.FileWriter;
import java.io.Writer;
public class WriteDemo02{
	public static void main(String[] args) throws Exception {//异常抛出,不处理
		//第 1 步:使用 File 类找到一个文件
		File f = new File("d:"+File.separator+"test.txt");//声明 File 对象
		//第 2 步:通过子类实例化父类对象
		Writer out = null;//准备好一个输出流的对象
		out = new FileWriter(f,true);//通过对象多态性,进行实例化
		//第 3 步:进行写操作
		String str = "\r\nI am chaoyi!!!\r\nYES!!!";//准备一个字符串
		out.write(str);//将内容输出
		//第 4 步关闭输出流
		out.close();//关闭输出流
	}
/* 结果:向文件中写入数据
 * Hello World!!!
 * I am chaoyi!!!
 * YES!!!
 * */
}

 

 

字符输入流:Reader
Reader是使用字符的方式从文件之中取出数据,Reader类的定义如下:
——public abstract class Reader extends Object implements Readable, Closeable
Reader本身也是抽象类,如果现在要从文件中读取内容,则可以直接使用FileReader子类。
——FileReader的构造方法定义如下:
————public FileReader(File file) throws FileNotFoundException

 

Reader类的常用方法
字节流与字符流

 

从文件中读取内容

import java.io.File;
import java.io.FileReader;
import java.io.Reader;
public class ReaderDemo01{
	public static void main(String[] args) throws Exception {//异常抛出,不处理
		//第 1 步:使用 File 类找到一个文件
		File f = new File("d:"+File.separator+"test.txt");//声明 File 对象
		//第 2 步:通过子类实例化父类对象
		Reader reader = null;//准备好一个输入流的对象
		reader = new FileReader(f);//通过对象多态性,进行实例化
		//第 3 步:进行读操作
		char c[] = new char[1024];//所有的内容读到此数组中
		int len = reader.read(c);//将内容输出
		//第 4 步关闭输入流
		reader.close();//关闭输入流
		System.out.println("内容为:"+new String(c,0,len));//把 char 数组变为字符串输出
	}
/* 结果:
 * 内容为:Hello Wrold!!
 * I am chaoyi!!!
 * YES!!!
 * */
}

 

使用循环的方式读取内容

import java.io.File;
import java.io.FileReader;
import java.io.Reader;
public class ReaderDemo02{
	public static void main(String[] args) throws Exception {//异常抛出,不处理
		//第 1 步:使用 File 类找到一个文件
		File f = new File("d:"+File.separator+"test.txt");//声明 File 对象
		//第 2 步:通过子类实例化父类对象
		Reader reader = null;//准备好一个输入流的对象
		reader = new FileReader(f);//通过对象多态性,进行实例化
		//第 3 步:进行读操作
		int len = 0;//用于记录读取的数据个数
		char c[] = new char[1024];//所有的内容读到此数组中
		int temp = 0;//接收读取的每一个内容
		while((temp = reader.read()) != -1){
			//将每次的读取内容给 temp 变量,如果 temp 的值不是 -1,则表示文件没有读完
			c[len] = (char)temp;
			len++;
		}
		//第 4 步关闭输入流
		reader.close();//关闭输入流
		System.out.println("内容为:"+new String(c,0,len));//把 char 数组变为字符串输出
	}
/* 结果:
 * 内容为:Hello Wrold!!
 * I am chaoyi!!!
 * YES!!!
 * */
}

 

字节流与字符流的区别
字节流在操作的时候本身是不会用到缓冲区(内存)的,是与文件本身直接操作的,而字符流在操作的时候是使用到缓冲区的。
字节流与字符流
 

字节流与字符流的选择
所有的文件在硬盘或在传输的时候都是以字节的方式进行的,包括图片等都是按字节的方式存储的,而字符是只有在内存中才会形成,所以在开发中,字节流使用较为广泛。

 

范例:文件拷贝
在dos命令中存在一个文件的拷贝命令(copy),例如:现在要将D盘中的test.txt文件拷贝到D盘中的demo.txt文件,则只要在命令行中输入copy即可完成:
copy命令的语法格式如下:
——copy 源文件 目标文件
字节流与字符流