12.3字节流与字符流基本操作 (血干JAVA系列)

12.3.1字节流

字节流主要是操作byte类型数据,以byte数组为准,主要操作类就是Outputstream类和
InputStream 类。

1.字节输出流:Outputstream

Outputstream是整个IO包中字节输出流的最大父类,此类的定义如下:

public abstract class Outputstream
extends Object
implements Closeable, Flushable
序 号 方法或常量 类 型 描 述 
1 public void close() throws IOException 普通 关闭输出流
2 public void flush() throws IOException 普通 刷新缓冲区
3 public void write(byte口 b) throws IOException 普通 将一个byte数组写入数据流
4 public void write (byte口 b, int of^ int len) throws 
IOException普通 将一个指定范围的byte数组 写入数据流
5 public abstract void write(int b) throws IOException普通 将一个字节数据写入数据流

此时可使用FileOutputStream子类,此类的构造方法如下:

public FileOutputStream(File file) throws FileNotFoundException

【例12.14】使用write(byte b[])的方式向文件中写入字符串

package jiaqi;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;

public class demo380_1 
{
	public static void main(String[] args)throws Exception
	{
		//找到一个文件
		File f=new File("d:" + File.separator + "test.txt");
		//实例化父对象
		OutputStream out = new FileOutputStream(f);
		
		String str="hello word!!!";
		
		//输出只能是byte
		byte b[] = str.getBytes();
		out.write(b);
		
		out.close();
	}
}

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

package jiaqi;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;

public class demo382_2 {

	public static void main(String[] args)throws Exception
	{
		// TODO 自动生成的方法存根
		File f = new File("d:" + File.separator + "test.txt");
		OutputStream out=new FileOutputStream(f);
		String str="hello wordl!!";
		byte b[]=str.getBytes();
		for(int i=0;i<b.length;i++)
		{
			out.write(b[i]);
		}
		out.close();
	}

}

2.追加新内容

之前的所有操作中,如果重新执行程序,则肯定会覆盖文件中的己有内容,那么此时可以通过FielOutputStream类的另一种构造方法进行实例化,向文件中追加内容,此构造方法如下所示:

public FileOutputStream(File file,boolean append) throws FileNotFoundException

在构造方法中,如果将append的值设置为true,则表示在文件的末尾追加内容。

【例12.16】修改之前的程序,追加文件内容

package jiaqi;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;

public class demo383_1 {

	public static void main(String[] args) throws Exception
	{
		File f = new File("d:" + File.separator + "test.txt");
		OutputStream out = new FileOutputStream(f,true);
		
		String str="hello word!!";
		byte b[]=str.getBytes();
		
		out.write(b);
		
		out.close();
	}

}

【例子】追加时加上换行

package jiaqi;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;

public class demo384_1 
{
	public static void main(String[] args)throws Exception 
	{
		File f = new File("d:" + File.separator + "test.txt");
		OutputStream out = new FileOutputStream(f,true);
		
		String str="\r\nhello word!!";
		byte b[] = str.getBytes();
		
		out.write(b);
		out.close();
		
	}

}

3.字节输入流:Inputstream

既然程序可以利用Outputstream类向文件中写入内容,则也可以通过InputStream类从文件中把内容读取进来。InputStream类的定义如下:

public abstract class InputStream extends Object
implements Closeable 

OutputStream类一样,InputStream本身也是一个抽象类,必须依靠其子类,如果现在是 从文件中读取,子类肯定是FilelnputStream
FilelnputStream类的构造方法如下:

public FilelnputStream(File file) throws FileNotFoundException
序号     方法或常量      类型     描述 
1 public int available() throws IOException 普通 可以取得输入文件的大小
2 public void close() throws IOException 普通 关闭输入流
3 public abstract int read() throws IOException 普通 读取内容,以数字的方式读取
4 public int read(byte[] b) throws IOException 普通 将内容读到byte数组之中,同时返回读入的个数

【例12.17】从文件中读取内容

package jiaqi;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;

public class demo385_1 {

	public static void main(String[] args)throws Exception 
	{
		// TODO 自动生成的方法存根
		File f = new File("d:"+ File.separator +"test.txt");
		InputStream input = new FileInputStream(f);
		
		byte b[] = new byte[1024];
		
		input.read(b);
		
		System.out.println(new String(b));
		
	}

}

结果:
Hello World!!
Hello World!
(后面会有大量的空格,此处省略其显示)
在这里插入图片描述

上面的程序中,内容己经被读取进来了,但是发现后面有很多个空格。因为开辟的byte数组大小为1024,而实际的内容才只有28个字节,也就是说存在了 998个空白的空间,在将byte数组变为字符串的时候也将这998个无用的空间转为字符串了,这样的操作肯定是不合理的。
如果要想解决以上的问题,则要观察read方法,在此方法上有一个返回值,此返回值表示向数组中写入了多少个数据。

【例12.18】修正以上的错误

package jiaqi;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

public class demo385_2
{
	public static void main(String[] args)throws Exception 
	{
		File f = new File("d:" + File.separator + "test.txt");
		InputStream input = new FileInputStream(f);
		
		byte b[] = new byte[1024];
		
		int len = input.read(b);
		
		System.out.println("长度" + len);
		System.out.println(new String(b,0,len));
	}
}

虽 然 指 定 了 b y t e 数 组 的 范 围 , 但 是 程 序 开 辟 很 多 的 空 问 , 会 造 成 资 源 的浪 费 , 那 么 能 否 根 据 文 件 的 数 据 量 来 选 择 开 辟 空 间 的 大 小 呢 ? 要 想 完 成 这 样 的 操 作 , 则 要 从 F i l e类中着手,因为在File类中存在一个length()方法,此方法就可以取得文件的大小。

【例12.19】开辟指定大小的byte数组

package jiaqi;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

public class demo386_1 
{
	public static void main(String arg[])throws Exception
	{
		File f = new File("d:" + File.separator + "test.txt");
		InputStream input = new FileInputStream(f);
		
		byte b[] = new byte[(int)f.length()];
		
		input.read(b);
		input.close();

		System.out.println(new String(b));
	}
}

除了以上的方式外,也可以通过循环,从文件中一个个地把内容读取进来,直接使用read()方法即可。

【例12.20】使用read()通过循环读取

package jiaqi;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

public class demo387_1 {

	public static void main(String[] args)throws Exception 
	{
		// TODO 自动生成的方法存根
		File f = new File("d:" + File.separator + "test.txt");
		InputStream input = new FileInputStream(f);
		
		byte b[] = new byte[(int)f.length()];
		
		for(int i=0;i<b.length;i++)
		b[i] = (byte)input.read();
		
		input.close();

		System.out.println(new String(b));
			
	}
}

上面程序是在明确知道了具体数组大小的前提下开展的,如果此时不知遣要输入的内容有多大,则只能通过判断是否读到文件末尾的方式来读取文件。

【例12.21】另一种方式的读取

package jiaqi;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

public class demo387_2 
{
	public static void main(String[] args)throws Exception
	{
		File f = new File("d:" + File.separator + "test.txt");
		InputStream input = new FileInputStream(f);
		
		int temp=0,len=0;
		byte b[] = new byte[1024];
		
		while((temp=input.read())!=-1)
		{
			b[len]=(byte)temp;
			len++;
		}
		
		input.close();
		
		System.out.println(len);
		System.out.println(new String(b,0,len));
	}
}

12.3.2字符流

在程序中一个字符等于两个字节,Java提供了 Reader和Writer两个专门操作字符流的类。

1.字符输出流Writer

Writer本身是一个字符流的输出类,此类的定义如下:

public abstract class Writer extends Object
implements Appendable, Closeable, Flushable

此类本身也是一个抽象类,如果要想使用此类,则肯定要使用其子类,此时如果是向文件中写入内容,应该使用FileWriter的子类
Writer类的常用方法

序号   方法或常量    类型述 
1 public abstract void close() throws lOException 普通 关闭输出流
2 public void write(String str) throws lOException 普通 将字符串输出
3 public void write(char[] ebuf) throws lOException 普通 将字符数组输出
4 public abstract void flush() throws lOException 普通 强制性清空缓存

FileWriter类的构造方法定义如下:

public FileWriter(File file) throws lOException

【例12.22】向文件中写入数据

package jiaqi;

import java.io.File;
import java.io.FileWriter;
import java.io.Writer;

public class demo389_1 
{
	public static void main(String[] args) throws Exception
	{
		// TODO 自动生成的方法存根
		File f = new File("d:" + File.separator + "test.txt");
		Writer out = new FileWriter(f);
		
		String str = "duyanhe";
		
		//outputstream write(byte b[])
		//writer  write(String str) 
		out.write(str);
		
		out.close();
	}

}

整个程序outputstream的操作流程并没有什么太大的区别,唯一的好处是,可以直接输出字符串,而不用将字符串变为byte数组之后再输出了。

2.使用FileWriter追加文件的内容

在使用字符流操作的时候,也可以实现文件的追加功能,直接使用FileWriter类中的以下构造即可实现追加:

public FileWriter(File file,boolean append) throws lOException 将append的值设置成true,就表示追加。

【例12.23】追加文件内容

package jiaqi;

import java.io.File;
import java.io.FileWriter;
import java.io.Writer;

public class demo389_2
{
	public static void main(String[] args)throws Exception 
	{
		File f = new File("d:" + File.separator + "test.txt");
		Writer out = new FileWriter(f,true);
		
		String str = "dyh\r\n";

		out.write(str);

		out.close();
	}
}

3.字符输入流:Reader

Reader类是使用字符的方式从文件之中取出数据,Reader的定义如下:

public abstract class Reader extends Object
implements Readable, Closeable 

Reader类本身也是抽象类,如果现在要从文件中读取内容,则可以直接使用FileReader子类。
Reader类的常用方法

序 号            方法或常量         类 型 描 述
1 public abstract void close() throws IOException 普通 关闭输出流
2 public int read() throws IOException 普通 读取单个字符
3 public int read(char[] cbuf) throws IOException 普通 将内容读到字符数组之中,返回读入的长度

FileReader的构造方法定义如下:

public FileReader(File file) throws FileNotFoundException

【例12.24】从文件中读取内容

package jiaqi;

import java.io.File;
import java.io.FileReader;
import java.io.Reader;

public class demo390_1 {

	public static void main(String[] args)throws Exception 
	{
		File f = new File("d:"+File.separator+"test.txt");
		Reader input =  new FileReader(f);
		
		char ch[] = new char[1024];
		
		int  len = input.read(ch);
		
		input.close();
		
		System.out.println("len:"+len);
		System.out.println(ch);
		
	}

}

如果此时不知道数据的长度,也可以像之前操作字节流那样,使用循环的方式进行内容的读取。

【例12.25]使用循环的方式读取内容

package jiaqi;

import java.io.File;
import java.io.FileReader;
import java.io.Reader;

public class demo391_1
{
	public static void main(String[] args) throws Exception
	{
		File f = new File("d:"+File.separator+"test.txt");
		Reader input =  new FileReader(f);
		
		char ch[] = new char[1024];
		int len=0,temp=0;
		
		while((temp=input.read())!=-1)
		{
			ch[len] = (char)temp;
			len++;
		}
		input.close();
	
		System.out.println("len"+len);
		System.out.println(new String(ch,0,len));
		
	}

}

12.3.3字节流与字符流的区别

字节流与字符流的使用非常相似,那么两者除了操作代码上的不同之外,是否还有其他的不同呢?
实际上字节流在操作的时候本身不会用到缓冲区(内存),是于文件本身直接操作,而字符流在操作时使用到缓冲区,通过缓冲区再操作文件.
在这里插入图片描述
下面以两个写文件的操作为例进行比较,但是在操作的时候字节流和字符流的操作完成后都不关闭输出流。

【例12.26】使用字节流不关闭执行

package jiaqi;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;

public class demo392_1 {

	public static void main(String[] args)throws Exception
	{
		// TODO 自动生成的方法存根
		File f = new File("d:"+File.separator+"test.txt");
		OutputStream out = new FileOutputStream(f);
		
		String str = "hello!!";
		
		byte b[] = str.getBytes();
		
		out.write(b);
		
				
	}

}

结果
在这里插入图片描述

此时,没有关闭字节流操作,但是文件中依然存在了输出的内容,证明字节流是直接操作文件本身的。而下面继续使用字符流完成,再观察效果。

【例12.27】使用字符流不关闭执行

package jiaqi;

import java.io.File;
import java.io.FileWriter;
import java.io.Writer;


public class demo393_1
{
	public static void main(String[] args)throws Exception 
	{
		File f = new File("d:"+File.separator+"test.txt");
		Writer out = new FileWriter(f);
		
		String str = "hello!!";
		out.write(str);
	}
}


结果
在这里插入图片描述

程 序 运 行 后 会 发 现 文 件 中 没 有 任 何 的 内 容 , 这 是 因 为 字 符 流 操 作 的 时 候 使 用 了 缓 冲 区 ,而 在 关 闭 字 符 流 的 时 候 会 强 制 性 地 将 缓 冲 区 中 的 内 容 进 行 输 出 , 但 是 如 果 程 序 没 有 关 闭 , 则 缓 冲区中的内容是无法输出的。 所以得出结论:字符流使用了缓冲区,而字节流没有使用缓冲区。

如 果 想 在 不 关 闭 的 时 候 也 可 以 将 字 符 流 的 内 容 全 部 输 出 , 则 可 以 使 用 Writer 类 中 的 flush ( )
方法完成。

【例12.28]强制性清空缓冲区

package jiaqi;

import java.io.File;
import java.io.FileWriter;
import java.io.Writer;

public class demo393_2 {

	public static void main(String[] args) throws Exception
	{
		File f = new File("d:"+File.separator+"test.txt");
		Writer out = new FileWriter(f);
		
		String str = "hello!!";
		out.write(str);
	
		out.flush();
	}

}

在这里插入图片描述

此时,文件中己经存在了内容,更进一步证明内容是保存在缓冲区的。这一点在读者的开发中要特别引起注意。

12.3.4范例——文件复制

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

【例12.29】实现复制功能

将程序中的异常,直接通过main抛出解决【与书上不同】

package jiaqi;

import java.io.*;
public class demo395_1
{

	public static void main(String[] args)throws Exception 
	{
		//参数个数不对
		if(args.length!=2)
		{
			System.out.println("输入参数不正确");
			System.out.println("例子:java demo395_1 源文件路径 目标文件路径");
			System.exit(1);
		}
		
		//读取两个参数
		File f1 = new File(args[0]);
		File f2 = new File(args[1]);
		
		//源文件存在
		if(f1.exists())
		{
			//打开
			InputStream input = new FileInputStream(f1);//读f1
			OutputStream out = new FileOutputStream(f2);//写f2
			
			if(input!=null&&out!=null)//判断输入输出是否准备好
			{
				int temp=0;
				while ((temp=input.read())!=-1) 
				{
					out.write(temp);
				}
				System.out.println("复制完成!!");	
			}
			//关闭
			input.close();
			out.close();
		}
		//源文件不存在
		else 
		{
			System.out.println("源文件不存在!!");
			System.exit(1);
		}
	}

}

结果
在这里插入图片描述
本 程 序 借 助 于 循 环 的 方 式 实 现 了 文 件 的 复 制 操 作 ,但 是 在 整 个 操 作 过 程 之 中 也 会 存 在 一 个问 题 , 即 每 次 只 能 够 复 制 一 个 字 节 , 如 果 文 件 量 小 的 程 序 还 可 以 忍 受 , 但 是 文 件 量 一 大 , 这 样的复制就很难使用了。为此可以进一步修改程序,实现一块一块数据的复制操作

【例12.30】修改数据复制程序

package jiaqi;

import java.io.*;
public class demo397_1
{

	public static void main(String[] args)throws Exception 
	{
		//参数个数不对
		if(args.length!=2)
		{
			System.out.println("输入参数不正确");
			System.out.println("例子:java demo395_1 源文件路径 目标文件路径");
			System.exit(1);
		}
		
		//读取两个参数
		File f1 = new File(args[0]);
		File f2 = new File(args[1]);
		
		//源文件存在
		if(f1.exists())
		{
			//打开
			InputStream input = new FileInputStream(f1);//读f1
			OutputStream out = new FileOutputStream(f2);//写f2
			byte b[] = new byte[1024];
			if(input!=null&&out!=null)//判断输入输出是否准备好
			{
				int temp=0;
				while ((temp=input.read(b))!=-1) 
				{
					out.write(b,0,temp);
				}
				System.out.println("复制完成!!");	
			}
			//关闭
			input.close();
			out.close();
		}
		//源文件不存在
		else 
		{
			System.out.println("源文件不存在!!");
			System.exit(1);
		}
	}

}

  • 28
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿斯卡码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值