字节流可以处理任意类型数据
字符流只能处理纯文本
在创建对象时,new后面报错,不是大圆形错,是小方块的错,就是异常,ctrl+1抛出异常信息
read()方法每次返回一个字节,为什么用int类型来接收?:
因为字节输入流可以操作任意类型的文件,比如图片文件,底层都是以二进制形式存储的,如果每次读取返回byte,有可能读到中间的时候读到11111111(是byte类型的-1)程序遇到-1就不读了,后面的就读不到了,如果用int类型接收,会在11111111前面补上24个0,凑足4个字节,那么byte类型的-1就变成了int类型的255,这样保证整个数据读完,而结束标记的-1就是int类型
write()的时候虽然是一个int数,但是会将前面的24个0去除,是一个byte数
package day20;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class Dk1CopyImage {
//拷贝图片(有多少个字节就有多少个来回,效率低,但是不占内存)
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("1.jpg"); //创建输入流对象,关联1.jpg
FileOutputStream fos = new FileOutputStream("2.jpg"); //创建输出流对象,关联2.jpg不用创建
int b;
while ((b = fis.read())!= -1) {
fos.write(b);
}
fis.close();
fos.close();
}
}
IO流字节读写原理:
package day20;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class Dk2CopyArray {
//以字节数组的形式将文件拷贝(只有一个来回,效率高,但是费内存不合适)
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("1.jpg"); //创建输入流对象,关联1.jpg
FileOutputStream fos = new FileOutputStream("2.jpg"); //创建输出流对象,关联2.jpg不用创建
byte[] arr = new byte[fis.available()]; //根据文件大小做一个字节数组
//如果read方法没有写参数,返回的就是读到的码表值,比原文件大得多,比如a对应的97,如果有参数读的就是字节个数
fis.read(arr); //将文件上的所有字节读取到数组中
fos.write(arr); //将数组上的所有字节写到文件上
fis.close();
fos.close();
}
}
package day20;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class Dk3CopySplitArray {
//以固定字节数组的形式将文件拷贝(推荐使用)
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("1.jpg"); //创建输入流对象,关联1.jpg
FileOutputStream fos = new FileOutputStream("2.jpg"); //创建输出流对象,关联2.jpg不用创建
int x;
byte[] arr = new byte[1024 *8]; //定义1024*8个大小做一个字节数组
//如果read方法没有写参数,返回的就是读到的码表值,比原文件大得多,比如a对应的97,如果有参数读的就是字节个数
while((x = fis.read(arr)) != -1) { //将文件上的两个字节读取到数组中,返回的x是字节个数
fos.write(arr,0,x); //从0开始取,到剩余的元素个数结束
}
fis.close();
fos.close();
}
}
上图中read()方法执行一次,就会将文件中的字节数据一次读取8192个字节存储在BufferedInputStream的缓冲区中,从缓冲区中返给一个一个字节返给b,如果write()一次先将缓冲区装满,然后再写到文件中,都是在内存中操作,减少了硬盘的操作次数。
Buffered会比自己定义字节数组(8192)稍慢一点,因为Buffered中读和写操作两个数组,自己定义是一个数组。
flush()和close()区别:
-
flush刷新之后还可以继续写
close在关闭之前会刷新一次,把缓冲区剩余的字节刷到文件中去,但是调用之后不能再写。使用缓冲区如果拷贝文件之后发现拷贝之后的文件比原文件小,那么可能是没有用close()方法。
-
需要实时刷新缓冲区内容的时候用flush(),close可以清空缓冲区。
字节流读取中文(需要进行转换)有弊端,可能会读到半个中文,解决办法有:
- 用字符流读(编码表+字节流)
- 将文件上所有字节一次读到内存上,在内存将所有字节转化为对应的字符串ByteArrayOutputStream
字节流写中文时必须转化为字节数组
注:在拷贝过程中中文不会出现问题(字节流可以拷贝任意数据,任意数据都是以字节形式存在的)
package day20;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class Dk4IoException {
//jdk1.6和1.7版本处理异常过程
public static void main(String[] args) throws IOException {
exception16();
exception17();
}
//jdk1.6
public static void exception16() throws IOException {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream("1.jpg");
fos = new FileOutputStream("2.jpg");
int b;
while ((b = fis.read())!= -1) {
fos.write(b);
}
} finally {
try {
if (fis != null) {
fis.close();
}
} finally {
if (fos != null) {
fos.close();
}
}
}
}
//jdk1.7
public static void exception17() throws IOException {
try (FileInputStream fis = new FileInputStream("1.jpg"); // 创建输入流对象,关联1.jpg
FileOutputStream fos = new FileOutputStream("2.jpg"); // 创建输出流对象,关联2.jpg不用创建
) {
int b;
while ((b = fis.read()) != -1) {
fos.write(b);
}
}//会自动关闭fis和fos
//FileInputStream和FileOutputStream实现了AutoClosable接口,会自动关闭
}
}
package day20;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Scanner;
public class Dk5ScannerWrite {
//将键盘录入的数据写到文件中,遇到quit就退出
public static void main(String[] args) throws IOException {
Scanner scanner = new Scanner(System.in);
FileOutputStream fos = new FileOutputStream("test.txt");
while(true) {
String line = scanner.nextLine();
if ("quit".equals(line)) {
break;
}
fos.write(line.getBytes()); //转化为字节数组
fos.write("\r\n".getBytes()); //每输入一次就换行
}
fos.close();
}
}