Java IO _字节流与字符流

1.掌握流的概念

2.掌握字节流与字符流的作用

3.掌握文件的标准操作步骤

4.掌握字节与字符操作的区别

1、流的概念


程序中的输入输出都是以流的形式保存的,流中保存的实际上全都是字节文件。

2、字节流与字符流


内容操作就四个类:OutputStream、InputStream、writer、Rader

使用 File 类操作的时候一定要有路径的问题,注意分隔符

实际上四个操作类都是抽象类

IO操作属于资源操作,对于资源操作,操作的最后必须关闭,否则就有可能出现未知错误。

3.字节流


Byte 是字节,肯定使用字节流操作。所有的数基本都可以直接使用 byte 数组表示出来。

字节输出流: OutputStream 类


Clonseable: 表示可以关闭的操作,因为程序运行到最后肯定要关闭。

Fluashable: 表示刷新,清空内存中的数据。

import java.io.File ;
import java.io.OutputStream ;
import java.io.FileOutputStream ;
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() ;						// 关闭输出流
	}
};

在操作的时候,如果文件本身不存在,则会为用户自动创建新文件。

在操作输出流的时候,也可以使用 write(int i) 的方法写出数据

import java.io.File ;
import java.io.OutputStream ;
import java.io.FileOutputStream ;
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() ;						// 关闭输出流
	}
};

以上的操作中在写入数据之后,文件之前的内容已经不存在了,因为在IO操作中默认的情况是将其进行覆盖的,那么如果现在要想执行追加的功能,则必须设置追加的操作,找到FileOutputStream 类;


import java.io.File ;
import java.io.OutputStream ;
import java.io.FileOutputStream ;
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() ;						// 关闭输出流
	}
};

程序本身是可以追加内容了,但是没有换行,是直接在末尾追加的。

如果在文件操作中想换行的话,使用  “\r\n” 完成。

import java.io.File ;
import java.io.OutputStream ;
import java.io.FileOutputStream ;
public class OutputStreamDemo04{
	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 = "\r\nHello World!!!" ;		// 准备一个字符串
		byte b[] = str.getBytes() ;			// 只能输出byte数组,所以将字符串变为byte数组
		for(int i=0;i<b.length;i++){		// 采用循环方式写入
			out.write(b[i]) ;	// 每次只写入一个内容
		}
		// 第4步、关闭输出流
		out.close() ;						// 关闭输出流
	}
};
字节输入流:InputStream


import java.io.File ;
import java.io.InputStream ;
import java.io.FileInputStream ;
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) ;		// 读取内容
		// 第4步、关闭输出流
		input.close() ;						// 关闭输出流
		System.out.println("内容为:" + new String(b)) ;	// 把byte数组变为字符串输出
	}
};
此时,内容确实已经读取进来了,但是可以发现存在问题。

import java.io.File ;
import java.io.InputStream ;
import java.io.FileInputStream ;
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数组变为字符串输出
	}
};
 这个代码还存在问题,现在文件没有这么大,但是开辟了这么大的数组空间,这样肯定很浪费,能不能根据文件大小来开辟数组空间呢?

如果要想知道文件大小,直接使用File 类即可。

import java.io.File ;
import java.io.InputStream ;
import java.io.FileInputStream ;
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()] ;		// 数组大小由文件决定
		int len = input.read(b) ;		// 读取内容
		// 第4步、关闭输出流
		input.close() ;						// 关闭输出流\
		System.out.println("读入数据的长度:" + len) ;
		System.out.println("内容为:" + new String(b)) ;	// 把byte数组变为字符串输出
	}
};
以上直接使用 byte 数组的方式完成的。

现在使用 public abstract int read() throws IOException 读取内容。

import java.io.File ;
import java.io.InputStream ;
import java.io.FileInputStream ;
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数组变为字符串输出
	}
};
以上的操作,只适合于知道输入流大小的时候,如果现在不知道大小呢?
import java.io.File ;
import java.io.InputStream ;
import java.io.FileInputStream ;
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步、进行读操作
		byte b[] = new byte[1024] ;		// 数组大小由文件决定
		int len = 0 ; 
		int temp = 0 ;			// 接收每一个读取进来的数据
		while((temp=input.read())!=-1){
			// 表示还有内容,文件没有读完
			b[len] = (byte)temp ;
			len++ ;
		}
		// 第4步、关闭输出流
		input.close() ;						// 关闭输出流\
		System.out.println("内容为:" + new String(b,0,len)) ;	// 把byte数组变为字符串输出
	}
};
当不知道读取内容有多在的时候,就只能以读取的数据是否为-1为读完的标志。
4.字符流

字符输出流



字符流的操作比字节流操作好在一点, 就是可以直接输出字符串了。不用再像之前那样进行转换操作了。

import java.io.File ;
import java.io.Writer ;
import java.io.FileWriter ;
public class WriterDemo01{
	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() ;						// 关闭输出流
	}
};

使用字符流默认请况下依然是覆盖已有的文件,如果要想追加的话,则直接在FileWrite 上增加一个可追加的标记即可。

import java.io.File ;
import java.io.Writer ;
import java.io.FileWriter ;
public class WriterDemo02{
	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\nLIXINGHUA\r\nHello World!!!" ;		// 准备一个字符串
		out.write(str) ;						// 将内容输出,保存文件
		// 第4步、关闭输出流
		out.close() ;						// 关闭输出流
	}
};
字符输入流:Reader


以字符数组的形式读取出数据。

import java.io.File ;
import java.io.Reader ;
import java.io.FileReader ;
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 input = null ;	// 准备好一个输入的对象
		input = new FileReader(f)  ;	// 通过对象多态性,进行实例化
		// 第3步、进行读操作
		char c[] = new char[1024] ;		// 所有的内容都读到此数组之中
		int len = input.read(c) ;		// 读取内容
		// 第4步、关闭输出流
		input.close() ;						// 关闭输出流
		System.out.println("内容为:" + new String(c,0,len)) ;	// 把字符数组变为字符串输出
	}
};

也可以使用循环的方式,通过文件是否讲到底的形式读取。

import java.io.File ;
import java.io.Reader ;
import java.io.FileReader ;
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 input = null ;	// 准备好一个输入的对象
		input = new FileReader(f)  ;	// 通过对象多态性,进行实例化
		// 第3步、进行读操作
		char c[] = new char[1024] ;		// 所有的内容都读到此数组之中
		int temp = 0 ;	// 接收每一个内容
		int len = 0 ;		// 读取内容
		while((temp=input.read())!=-1){
			// 如果不是-1就表示还有内容,可以继续读取
			c[len] = (char)temp ;
			len++ ;
		}
		// 第4步、关闭输出流
		input.close() ;						// 关闭输出流
		System.out.println("内容为:" + new String(c,0,len)) ;	// 把字符数组变为字符串输出
	}
};
5.字节流与字符流的区别

字节流和字符流使用是非常相似的,那么除了操作代码的不同之外,还有那些不同呢?

通过一个代码来验证字符流使用到了缓存。

import java.io.File ;
import java.io.OutputStream ;
import java.io.FileOutputStream ;
public class OutputStreamDemo05{
	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() ;						// 关闭输出流
	}
};
在使用字节流操作中,即使没有关闭,最终也是可以输出的。

import java.io.File ;
import java.io.Writer ;
import java.io.FileWriter ;
public class WriterDemo03{
	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() ;						// 此时,没有关闭
	}
};

以上的操作,没有输出任何内容出来,也就是说,所有的内容现在都是保存在了缓冲区中,而如果执行关闭的时候会强制性的刷新缓冲区,所以可以把内容输出。

如果现在假设,没有关闭的话,也可以手式强制性调用刷新方法。

public abstract void flush()throws IOException

import java.io.File ;
import java.io.Writer ;
import java.io.FileWriter ;
public class WriterDemo04{
	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.flush() ;	// 强制性清空缓冲区中的内容
		// out.close() ;						// 此时,没有关闭
	}
};
问题:

开发中是使用字节流好还是字符流好。

在所有的硬盘上保存文件或是进行传输的时候都是以字节的方式进行的,包括图片也是按字节完成,而字符是只有在内存中才会形成的,所以使用字节的操作是最多的。

6.操作范例


操作的时候要求可以按照如下的格式进行:

java Copy 源文件 目标文件

如果要采用以上的格式,则肯定要使用初始化参数的形式,输入两个路径,所以此时就必须输入参数的个数进行验证,判断其是否为 2

是使用字符流还是使用字节流呢? 肯定使用字节流,因为万一拷贝的是一个图片的。

要完成拷贝程序,两种方式可以采用:

实现一:将源文件中的内容全部读取进来,之后一次性写入到目标文件

实现二:边读边写的方式

很明显,使用第二种方式

import java.io.* ;
public class Copy{
	public static void main(String args[]){
		if(args.length!=2){		// 判断是否是两个参数
			System.out.println("输入的参数不正确。") ;
			System.out.println("例:java Copy 源文件路径 目标文件路径") ;
			System.exit(1) ;	// 系统退出
		}
		File f1 = new File(args[0]) ;	// 源文件的File对象
		File f2 = new File(args[1]) ;	// 目标文件的File对象
		if(!f1.exists()){
			System.out.println("源文件不存在!") ;
			System.exit(1) ;
		}
		InputStream input = null ;		// 准备好输入流对象,读取源文件
		OutputStream out = null ;		// 准备好输出流对象,写入目标文件
		try{
			input = new FileInputStream(f1) ;
		}catch(FileNotFoundException e){
			e.printStackTrace() ;
		}
		try{
			out = new FileOutputStream(f2) ;
		}catch(FileNotFoundException e){
			e.printStackTrace() ;
		}
		if(input!=null && out!=null){	// 判断输入或输出是否准备好
			int temp = 0 ;	
			try{
				while((temp=input.read())!=-1){	// 开始拷贝
					out.write(temp) ;	// 边读边写
				}
				System.out.println("拷贝完成!") ;
			}catch(IOException e){
				e.printStackTrace() ;
				System.out.println("拷贝失败!") ;
			}
			try{
				input.close() ;		// 关闭
				out.close() ;		// 关闭
			}catch(IOException e){
				e.printStackTrace() ;
			}
		}
	}	
}
总结:

1、掌握流的概念

2、掌握字节流和字符流操作文件的基本步骤

本章是以文件为例,实际上以后的所有操作都可以通过此段代码完成

3、字节流和字符流的区别

字节流:使用和到了缓冲区

4、边读、边写的方式在日后的开发中非常有用处。



  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值