Java之IO流 FileInputStream FileOutputStream

本文深入探讨了字节流的基本概念、常用类如FileInputStream、FileOutputStream及其操作方法,包括read和write的内部机制,解释了为何返回值是int而非byte。通过多个示例代码,演示了字节流在文件读写、复制、缓存操作、异常处理、文件加密解密等场景的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

字节流(能够处理任何类型的数据 因为计算机储存都是以字节为单位 byte 一个字节八位)
总类为
字节输入流 InputStream 连接硬盘和内存之间的管道 读取字节
字节输出流 OutputStream 从内存输出到硬盘中
下面讲些常用的类

FileInputStream

注意在输入的时候 方法中要抛出 IOException 异常(因为可能读入的过程中硬盘中可能没有此文件)
1.read() 方法 返回是个int值 其含义是文件数据中的码表值 如a为97 b为98 。。
2.read(byte[ ])返回也是int值 其含义是读入byte中的有效数据个数
3.read(byte[ ] ,int off ,int len)其中off表示起始偏移量 然后len表示 有效数据个数

一套典型的io流读入代码

	FileInputStream fis = new FileInputStream("xxx.txt");	//创建流对象
		int b;
		while((b = fis.read()) != -1) {
			System.out.println(b);
		}
		
		fis.close();

下面说说 为什么read 和 write 的返回值是int 而不是byte
按道理说文件不都是以byte为基本单位存储的吗?干嘛用int呢?
别着急
在此之前你要明白 io流中有一个机制 那就是当文件读入完的时候 指针将会指向-1 来表示文件读入或输出结束
假设 : 我用byte来作为返回值的话 读入的过程中 可能会出现 11111111 这也是-1的补码(计算机存储的二进制都是补码格式 原码取反加1)
-1 的原码
10000001
-1的反码(第一位表示为符号位)
11111110
-1的补码(反码加1)
11111111
那么就会出现自动返回的情况 导致文件没有完全读入或输出

那么用int 的话 会默认给byte的数 自动添加 24个0 来消除这种情况
而结束的时候在用 int的-1来指向结束就好了 同时也不用担心在java中输出的时候前面的24个0会自动给删掉 保证都是以原来的形式输出

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

public class Demo1_FileInputStream {

	/**
	 * @param args
	 * @throws IOException  
	 * read()方法读取的是一个字节,为什么返回是int,而不是byte
	 * 
	 * 00010100 00100100 01000001 11111111 0000000
	 * 
	 * 10000001    byte类型-1的原码
	 * 11111110	   -1的反码
	 * 11111111    -1的补码
	 * 
	 * 00000000 00000000 00000000 11111111
	 */
	public static void main(String[] args) throws IOException {
		//demo1();
		FileInputStream fis = new FileInputStream("xxx.txt");	//创建流对象
		int b;
		while((b = fis.read()) != -1) {
			System.out.println(b);
		}
		
		fis.close();
	}

	public static void demo1() throws FileNotFoundException, IOException {
		FileInputStream fis = new FileInputStream("xxx.txt");	//创建流对象
		int x = fis.read();										//从硬盘上读取一个字节
		System.out.println(x);
		int y = fis.read();
		System.out.println(y);
		int z = fis.read();
		System.out.println(z);
		int a = fis.read();
		System.out.println(a);
		int b = fis.read();
		System.out.println(b);
		fis.close();											//关流释放资源
	}

}

FileOutputStream

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

public class Demo2_FileOutputStream {

	/**
	 * @param args
	 * @throws IOException 
	 * FileOutputStream在创建对象的时候是如果没有这个文件会帮我创建出来
	 * 如果有这个文件就会先将文件清空
	 */
	public static void main(String[] args) throws IOException {
		//demo1();
		FileOutputStream fos = new FileOutputStream("yyy.txt",true);	//如果想续写就在第二个参数传true
		fos.write(97);
		fos.write(98);
		
		fos.close();
	}

	public static void demo1() throws FileNotFoundException, IOException {
		FileOutputStream fos = new FileOutputStream("yyy.txt");		//创建字节输出流对象,如果没有就自动创建一个
		//fos.write(97);				//虽然写出的是一个int数,但是到文件上的是一个字节,会自动去除前三个8位
		//fos.write(98);
		//fos.write(99);
		fos.write(100);
		fos.close();
	}

}

实际操作中都是两者结合一起使用
1.从demo1中可以看出来 输入输出的效率特别低
就好像我买100个鸡蛋 我一次买一个回来 这么一次次的来来回回
2.从demo3中可以看出来 使用大数组的话
就好像我买100个鸡蛋 我拿个容器(数组)一次装100个 拿回来就行
注意其中的
int len = fis.available(); 表示获取文件的字节个数
可是有个问题 那我字节个数100万呢? 我容器是不是得炸掉了?所以这种方法也不行

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

public class Demo3_Copy {

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		//demo1();
		//demo2();
		//demo3();
	}

	public static void demo3() throws FileNotFoundException, IOException {
		//第二种拷贝,不推荐使用,因为有可能会导致内存溢出
		FileInputStream fis = new FileInputStream("致青春.mp3");		//创建输入流对象,关联致青春.mp3
		FileOutputStream fos = new FileOutputStream("copy.mp3");	//创建输出流对象,关联copy.mp3
		//int len = fis.available();
		//System.out.println(len);
		
		byte[] arr = new byte[fis.available()];						//创建与文件一样大小的字节数组
		fis.read(arr);												//将文件上的字节读取到内存中
		fos.write(arr);												//将字节数组中的字节数据写到文件上
		
		fis.close();
		fos.close();
	}

	public static void demo2() throws FileNotFoundException, IOException {
		FileInputStream fis = new FileInputStream("致青春.mp3");		//创建输入流对象,关联致青春.mp3
		FileOutputStream fos = new FileOutputStream("copy.mp3");	//创建输出流对象,关联copy.mp3
		
		int b;
		while((b = fis.read()) != -1) {								//在不断的读取每一个字节
			fos.write(b);											//将每一个字节写出
		}
		
		fis.close();												//关流释放资源
		fos.close();
	}

	public static void demo1() throws FileNotFoundException, IOException {
		FileInputStream fis = new FileInputStream("双元.jpg");		//创建输入流对象,关联双元.jpg
		FileOutputStream fos = new FileOutputStream("copy.jpg");	//创建输出流对象,关联copy.jpg
		
		int b;
		while((b = fis.read()) != -1) {								//在不断的读取每一个字节
			fos.write(b);											//将每一个字节写出
		}
		
		fis.close();												//关流释放资源
		fos.close();
	}

}

这是最新的一种方法
小数组的标准格式

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

public class Demo4_ArrayCopy {

	/**
	 * @param args
	 * 第三种拷贝
	 * 定义小数组
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		//demo1();
		//demo2();
		FileInputStream fis = new FileInputStream("致青春.mp3");
		FileOutputStream fos = new FileOutputStream("copy.mp3");
		
		byte[] arr = new byte[1024 * 8];
		int len;
		while((len = fis.read(arr)) != -1) {				//如果忘记加arr,返回的就不是读取的字节个数,而是字节的码表值
			fos.write(arr,0,len);
		}
		
		fis.close();
		fos.close();
	}

	public static void demo2() throws FileNotFoundException, IOException {
		FileInputStream fis = new FileInputStream("xxx.txt");
		FileOutputStream fos = new FileOutputStream("yyy.txt");
		
		byte[] arr = new byte[2];
		int len;
		while((len = fis.read(arr)) != -1) {
			fos.write(arr,0,len);
		}
		
		fis.close();
		fos.close();
	}

	public static void demo1() throws FileNotFoundException, IOException {
		FileInputStream fis = new FileInputStream("xxx.txt");
		byte[] arr = new byte[2];
		int a = fis.read(arr);						//将文件上的字节读取到字节数组中
		
		System.out.println(a);						//读到的有效字节个数
		for (byte b : arr) {						//第一次获取到文件上的a和b
			System.out.println(b);
		}
		System.out.println("-----------------------");
		int c = fis.read(arr);
		System.out.println(c);
		for (byte b : arr) {
			System.out.println(b);
		}
		fis.close();
	}

}

BufferedInputStream
BufferedOutputStream
带缓存的输入输出流 缓存大小为1024*8 = 8192
缓存是由内存来存储的 故运算速度比硬盘要快很多
在这里插入图片描述
一套超级经典的使用缓存IO流操作

public static void main(String[] args) throws IOException {
		//demo1();
		//flush和close方法的区别
		BufferedInputStream bis = new BufferedInputStream(new FileInputStream("致青春.mp3"));
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.mp3"));
		
		int b;
		while((b = bis.read()) != -1) {
			bos.write(b);
		}
		bis.close();
		bos.close();
	}

flush
主要用途是用来实时刷新 如QQ聊天中的数据缓存
原因:如果不刷新的话 缓存必须要存到指定大小才能结束 否则不会接受
这也是为什么要刷新的原因了
close
close方法既可以关闭流 同时还自带刷新的功能 不过只能用一次用完就关闭
因此对于一次性的IO流操作就可以直接用close而不需要去用flush

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class Demo5_BufferCopy {

	/**
	 * @param args
	 * @throws IOException 
	 * close方法
	 * 具备刷新的功能,在关闭流之前,就会先刷新一次缓冲区,将缓冲区的字节全都刷新到文件上,再关闭,close方法刷完之后就能写了
	 * flush方法?
	 * 具备刷新的功能,刷完之后还可以继续写
	 */
	public static void main(String[] args) throws IOException {
		//demo1();
		//flush和close方法的区别
		BufferedInputStream bis = new BufferedInputStream(new FileInputStream("致青春.mp3"));
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.mp3"));
		
		int b;
		while((b = bis.read()) != -1) {
			bos.write(b);
		}
		bis.close();
		bos.close();
	}

	public static void demo1() throws FileNotFoundException, IOException {
		FileInputStream fis = new FileInputStream("致青春.mp3");				//创建输入流对象,关联致青春.mp3
		FileOutputStream fos = new FileOutputStream("copy.mp3");			//创建输出流对象,关联copy.mp3
		BufferedInputStream bis = new BufferedInputStream(fis);				//创建缓冲区对象,对输入流进行包装让其变得更加强大
		BufferedOutputStream bos = new BufferedOutputStream(fos);
		
		int b;
		while((b = bis.read()) != -1) {
			bos.write(b);
		}
		
		bis.close();
		bos.close();
	}

}

字节流不好处理 中文
1.在读取的过程中会出现乱码(因为中文占两个字节 还有标点符号)
2.在写出的过程中 要把字符内容转换成字节数组 并且换行的时候是“\r\n”

标准IO流处理异常
1.7的新特性
try(可以存放实现了自动关闭的类)

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Main{
	
	public static void main(String[] args) throws Exception {
		try(
			BufferedInputStream bis = new BufferedInputStream(new FileInputStream("aaa.txt"));
			BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("aaacopy.txt"));
			Myclose mc  = new Myclose();
		)
		{
			int b;
			while((b = bis.read()) != -1) {
				bos.write(b);
			}
		}
		
	}
}
class Myclose implements AutoCloseable{

	@Override
	public void close() throws Exception {
		System.out.println("自动关闭中");
	}
}

文件加密

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class Main{
	public static void main(String[] args) throws Exception {
		try(
				BufferedInputStream bis = new BufferedInputStream(new FileInputStream("aaa.txt"));
				BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("aaacopy1.txt"));
			)
			{
				int b;
				while((b = bis.read()) != -1) {
					bos.write(b ^ 123);
				}
			}
	}
}

文件解密
核心思想就是两次 ^ 运算后数值为本事
所以123 也就是密匙 !

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class Main{
	public static void main(String[] args) throws Exception {
		try(
				BufferedInputStream bis = new BufferedInputStream(new FileInputStream("aaacopy1.txt"));
				BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("aaacopy1jiemi.txt"));
			)
			{
				int b;
				while((b = bis.read()) != -1) {
					bos.write(b ^ 123);
				}
			}
	}
}

控制台输入文件路径拷贝到当前项目下

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Scanner;

public class Main{
	public static void main(String[] args) throws Exception {
		File file = getFile();
		BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file.getName()));
		int b;
		while((b = bis.read()) != -1) {
			bos.write(b);
		}
		bis.close();
		bos.close();
	}

	public static File getFile() {
		System.out.println("请输入您的路径:");
		Scanner sc  = new Scanner(System.in);
		String line = sc.nextLine();
		while(true) {
			File file = new File(line);
			if(!file.exists()) {
				System.out.println("文件路径不存在 请重新输入:");
			}else if(file.isDirectory()) {
				System.out.println("您是文件夹路径 请重新输入:");
			}else {
				return file;
			}
		}
	}
}

输入数据 然后保存到text.txt文件中

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.util.Scanner;

public class Main{
	
	public static void main(String[] args) throws Exception {
		Scanner sc = new Scanner(System.in);
		//第二个参数为true 表示可追加
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("text.txt",true)); 
		while(true) {
			String line = sc.nextLine();
			if(line.equals("quit")) {
				break;
			}
			bos.write(line.getBytes());
			bos.write("\r\n".getBytes());
		}
		bos.close();
		
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

黑瞳丶

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

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

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

打赏作者

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

抵扣说明:

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

余额充值