文件字节输出流,输入流

文章目录

字节输入流 InputStream

在这里插入图片描述

字节输出流 OutputStream

在这里插入图片描述

文件字节输入流 FileInputStream

构造方法:

1 FileInputStream(File file) 通过指定的文件建立输入流通道
FileInputStream fis=new FileInputStream(new File("1.txt"));
2 FileInputStream(String name) 通过字符串的路径建立输入流通道。
FileInputStream fis=new FileInputStream("1.txt");
注意:如果文件找不到,报异常 FileNotFoundException构造方法只能封装文件路径,封装文件夹路径是没意义的,因为他本来就是空的,不过可以遍历文件夹,在分别读文件。

常用方法

1.read() 从输入流中读取一个字节。

如果达到文件的末尾,返回-1.(返回值是byte数据转成的int。如:文件的a返回97)
测试数据,在项目下有一个 1.txt 文件,里面保存abc

		FileInputStream fis=new FileInputStream(new File("1.txt"));
		int result =0;
		while((result=fis.read())!=-1) {
			System.out.print(result);
			System.out.println((char)result);
		}
		fis.close();

结果:
97a
98b
99c

2.read(byte[] b)将 最多b.length个数据读取到字节数组中.

注意: 返回值是读取到的字节个数。读取到的数据放在了字节数组中。 如果达到文件的末尾,返回-1
理解:java中他的源码是调用的native修饰的 方法,看不见是怎么实现的。大概应该是用的c语言实现的。read(byte[] b)获取每个字节放进byte数组里,最多放数组的长度个。如数组是new byte[1024],就可以放1024个字节

使用:
public void static void main(String[] args)throws IOException{
	FileInputStream fis=new FileInputStream(new File("1.txt"));
	//定义一个用来存储数据的byte数组
	byte[] bytes = new byte[1024];//数组的长度可以是任意值,通常情况下为1024。或1024的倍数
	//定义一个int类型,接受返回值,即读取到的个数,给他默认值0
	int readNum = 0;
	while ((readNum = fis.read(bytes)) != -1){
		//把每个byte数组转为字符串
		System.out.println(new String(bytes,0,readNum));
	}
	fis.close();
}
代码解释:

理解:使用方法中,会用while循环,循环往数组里放,那么会有三种情况,1,数组没满,但是文件读完了。 那么直接返回读到个字节数。再走继续read就是-1,退出循环。2,数组满了,文件刚好读完了。然后又一次while循环,返回-1,退出循环。3,数组满了,但是文件没有读完。就再循环一次,从数组中挨个覆盖,如果第二次到数组存到一半,文件读完了,就会返回这次读到的个数,注意,这时数组上半部分是最后一次读的,后半部分是上一次读的后部分,就是第二次循环的时候他不会清空数组,而是挨个覆盖。然后再次循环返回-1,退出循环。
细节通过 new String(bytes,offset,count) 构造方法,转换成字符串
其中 ,bytes表示数组,offset偏移量表示从哪个位置开始进行转换,count表示读取的个数。
为什么要用这个String(bytes,offset,count)构造方法? 因为byte数组中没有存放读取字节的,里边都是0,如果一个文件只有3个字节,但是数组长度是1024,那么直接输出数组,他会有1021个没用的0,只有3个 是我们想要的。(在下一个构造方法中会体现出来)所以用String(bytes,offset,count) 只获取读取到的长度,解决上述问题。

3 read(byte[] b, int off, int len) 从数组off索引位置开始放入,读取的长度为len 返回值是读取的个数。
实例
public static void main(String[] args) throws IOException {
		FileInputStream fis=new FileInputStream("1.txt");
		byte[] b=new byte[10];
		int value = fis.read(b, 3, 3);
		System.out.println(value);
		System.out.println(Arrays.toString(b));
		System.out.println(new String(b,3,value));
		fis.close();
	}

输出结果:
3
[0, 0, 0, 97, 98, 99, 0, 0, 0, 0]
abc

注意

从返回结果可以看出来,数组里没有存放读取的字节的都是0.

4 close() 关闭资源,每次使用完成都要关闭资源
5 available() 返回读取的文件的剩余字节数,如果没有调用read方法,就是文件的总字节数。

文件字节输出流 FileOutputStream

构造方法

1 FileOutputStream(File file) /2 FileOutputStream(String name) 创建一个输出流。该输出流会自动创建一个新的文件或者覆盖原文件
3 FileOutputStream(File file, boolean append) /4 FileOutputStream(String name, boolean append)

创建一个输出流,该输出流当第二个参数的值为true的时候,从文件末尾插入,不覆盖。第二个参数值为false 时与没有append参数一样,直接覆盖。

常用方法

① write(int b) 将一个字节数据写入到文件中。

int b 指字节对应的ASCII值,这个时候,会将int类型转成byte类型存储。
byte转int在这个帖子有介绍

② write(byte[] b)将一个数组的字节写入到文件中。
实例

String类型转byte数组。str.getBytes();

public static void main(String[] args)throws IOException{
	FileOutputStream  fos=new FileOutputStream("1.txt");
	fos.write("随便写一个String转成byte数组".getBytes());
	fos.close();
}
③ write(byte[] b, int off, int len) 从指定的off索引位置开始写入,写入len个数组的数据。

在复制文件的时候用。看复制图片例子

④ close() 关闭资源

高效读取的字节流

缓冲区的字节流 : 自身内部包含缓冲区,即数组,该数组长度为8192个。用法跟文件字节流基本一样,只是比较高效。

文件字节缓冲输入流 BufferedInputStream

构造方法

BufferedInputStream(InputStream in)

常用方法

read(byte[] )

文件字节缓冲输出流 BufferedOutputStream

构造方法

BufferedOutputStream(OutputStream out)

常用方法

write(byte[] ,off,len)

注意,缓冲流多一个flush()方法;flush是将缓冲区的数据刷新到文件中。close()是关闭流,这个流就不能使用了,但是close之前会调用flush方法。

用法(复制图片):

这个是缓冲字节流实现的,用字节流同理。(注意:write必须用write(bytes,0,readNum)这个方法,不然最后一次可能会多出来一段倒数第二次读到的数据,也可能多出来空的。因为read(byte[] b)的特点,在上边有)

	public class BufferedInputStudy {
	public static void main(String[] args) throws IOException {
		BufferedInputStream bis = new BufferedInputStream(
				new FileInputStream(new File("C:\\Users\\Administrator\\Desktop\\logo.png")));
		
		BufferedOutputStream bos = new BufferedOutputStream(
				new FileOutputStream(new File("C:\\Users\\Administrator\\Desktop\\logo-copy.png")));
		
		byte[] bytes = new byte[1024];
		int readNum = 0;
		while ((readNum = bis.read(bytes)) != -1) {
			bos.write(bytes,0,readNum);
		}
		
		//输出流必须关,不然输出不全,或者不输出??
		bis.close();
		bos.close();
	}

流的异常处理形式

jdk 1.6 以复制文件为例

格式:

	try{
		..... 	
		}catch(){
		 处理异常 .... 
		 } finally{
		  关闭流....
		  }

用法:

public static void main(String[] args) {
		//提升作用域
		FileInputStream fis =null;
		FileOutputStream fos=null;
		try {
			int i=5/0;//这个时候抛出除零异常,流是null,关闭流会报空指针,所以关闭资源的时候需要判断
			fis = new FileInputStream(new File("1.txt"));
			fos = new FileOutputStream(new File("3.txt"));
			int readNum=0;
			byte[] b=new byte[1024];
			while((readNum=fis.read(b))!=-1) {
				fos.write(b,0,readNum);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
//			关闭资源。
			try {
				//判断流是否为null 不为空才可以关闭(重要)
				if (fis!=null) {
					fis.close();
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			try {
				//判断流是否为null 不为空才可以关闭(重要)
				if (fos!=null) {
					fos.close();
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

一定要记得关闭流的时候,判断是否为空

jdk 1.7

try-with-resources格式
用法:

public static void main(String[] args) {
		try(
			FileInputStream fis=new FileInputStream(new File("1.txt"));
			FileOutputStream fos=new FileOutputStream(new File("3.txt"));
		 ){
			int value=0;
			byte[] b=new byte[1024];
			while((value=fis.read(b))!=-1) {
				fos.write(b,0,value);
			}
		}catch (Exception e) {
			e.printStackTrace();
		}
	}

注意

创建字节输入流( FileInputStream)的时候,路径找不到会抛异常,创建字节输出流(FileOutputStream)的时候,路径中的文件或目录没有就创建,有一样的就覆盖。
读写效率:用byte[]的读写方法比直接read()和write()效率高。
缓冲字节流改进了字节流,比一般字节流效率高

递归实现复制目录

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 作者: 帅的一批 时间:2019年12月12日下午4:12:45 学习: 内容: 复制一个文件夹到另一个文件夹
 */
public class CopyFiles {
	public static void main(String[] args) throws IOException {
		File f1 = new File("E:\\File");
		File f2 = new File("E:\\File1");
		copyFiles2(f1, f2);
	}

	//单纯的复制文件
	public static void copyFile2(File f1, File f2) throws IOException {
		FileInputStream fis1 = new FileInputStream(f1);
		FileOutputStream fos2 = new FileOutputStream(f2);
		int readNum = 0;
		byte[] bytes = new byte[1024];
		while ((readNum = fis1.read(bytes)) != -1) {
			fos2.write(bytes, 0, readNum);
		}
		System.out.println("复制文件" + f1.getAbsolutePath() + "到" + f2.getAbsolutePath() + "成功。");
	}
	/**
	 * 
	 * @param f1 把f1复制一份给f2
	 * @param f2 把f1复制一份给f2
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	public static void copyFiles2(File f1, File f2) throws FileNotFoundException, IOException {

		if (f1.getAbsolutePath().equals(f2.getAbsolutePath())) {
			System.out.println("路径名一样,再见来不及握手。");
			return;
		} else if (!f1.exists()) {
			System.out.println("文件或目录不存在,再见来不及握手");
			return;
		} else if (f2.getName().contains(".")) {
			System.out.println("复制到的目录名格式错误,不要包含 '.' ");
			return;
		}

		// 如果都是文件就复制
		if (f1.isFile()) {
			System.out.println("创建" + f2.getAbsolutePath() + "目录:" + f2.mkdir());
			File newF2 = new File(f2.getAbsolutePath() + "//" + f1.getName());
			copyFile2(f1, newF2);
		}
		// 如果都是目录,就遍历copy
		if (f1.isDirectory()) {
			File[] files = f1.listFiles();
			if (files != null) {
				for (File file : files) {
					// 创建新文件路径,这个文件或文件夹与父目录一一对应。
					File newFile = new File(f2.getAbsolutePath() + "\\" + file.getName());
					// 如果是文件夹就创建文件夹,如果是文件就创建文件;如果是文件夹,就继续遍历,一直找到文件为止;找到文件就复制
					if (file.isDirectory()) {
						// 目录 创建目录,修改流,再递归
						// File newFile = new File(f2.getAbsolutePath() + "\\" + file.getName());
						System.out.println("创建" + newFile.getAbsolutePath() + "文件夹:" + newFile.mkdirs());
						copyFiles2(file, newFile);
					} else {
						// File newFile = new File(f2.getAbsolutePath() + "\\" + file.getName());
						copyFile2(file, newFile);
					}
				}
			}
		}
	}
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值