一、字节流
文件字节流
字节流的两个抽象父类:字节输出流:OutputStream和字节输入流:InputStream
1、字节输出流:OutputStream
这个抽象类是表示字节输出流的所有类的超类。 输出流接收输出字节并将其发送到某个接收器。
- 查看API可以知道,字节流写数据一共有三种方式:
- public void write(int b) :写入一个字节
- public void write(byte[] b):写入一个字节数组
- public void write(byte[] b,int off,int len):写入一个字节数组的一部分
- close():关闭此文件输入流,并释放与流相关的所有系统资源
- 使用字节输出流写入数据:使用 OutputStream 它的子类 FileOutputStream
- FileOutputStream 类的构造方法:
- FileOutputStream(File file)
- FileOutputStream(String name)
- FileOutputStream 类的构造方法:
- 字节输出流写入数据的操作步骤:
- 第一步:创建字节输出流对象 ,并指定文件路径,不指定文件路径默认在项目路径。如果该路径没有该文件,创建字节输入流对象会将该文件创建出来
- 第二步:用输出流对象点 write() 方法,根据传入的参数确认调用的那个写入的方法,并将参数内容写入流对象指定的文件中
- 第三步:关闭流对象
-
Demo代码示例
public class FileOutputStreamDemo { public static void main(String[] args) throws IOException { // 创建字节输出流对象(FileOutputStream的这两种构造方法效果是一样的用那个都可以) // FileOutputStream(File file) // File file = new File("fos.txt"); // FileOutputStream fos = new FileOutputStream(file); //构造方法: FileOutputStream(String name) FileOutputStream fos = new FileOutputStream("fos.txt"); try { // 调用write()方法,向fos文件中写入数据,写入一个字节 fos.write(97); //输出结果是97 -- 底层二进制数据 -- 通过记事本打开 -- 找97对应的字符值 -- a //换行 fos.write("\r\n".getBytes()); //public void write(byte[] b):写一个字节数组 byte[] bys={97,98,99,100,101}; fos.write(bys);//输出结果是abcde //换行 fos.write("\r\n".getBytes()); //public void write(byte[] b,int off,int len):写一个字节数组的一部分,存储数据下标范围 fos.write(bys,1,3);//输出结果是bcd //换行 fos.write("\r\n".getBytes()); //调用write()方法,向fos文件中写入数据,写入一段字符串并转换成 Byte 数组 fos.write("HelloWorld\t".getBytes()); fos.write("JAVA\t".getBytes()); } catch (IOException e) { e.printStackTrace(); } finally { //释放资源,这一步很重要,如果不关闭流,流对象就会始终存在,占用的内容空间!!! //关闭此文件输出流并释放与此流有关的所有系统资源。 fos.close(); } } }
运行结果:
运行程序,完成之后刷新项目,就可以看到创建的fos.txt的文件,并且里面的内容是写入数据的内容 :
最后,为什么使用完流之后一定要使用 close() 方法将流关闭呢?
如果不关闭流,流对象就会始终存在,占用的内容空间!所以使用该方法让流对象变成垃圾,这样就可以被垃圾回收器回收了。
字节输出流操作步骤:
A:创建字节输出流对象
B:写数据
C:释放资源
我们在写代码时候,一定要先将问题总结出来,不然容易将自己搞得很混乱,代码质量也不高。所以要一步一步的将功能的整体实现步骤总结出来,这样会让你的思路更清晰,代码写的更流畅!
2、字节输入流:InputStream
这个抽象类是表示字节输入流的所有类的超类。
-
使用字节输入流读取数据:使用 InputStream的子类FileInputStream
- FileInputStream 类的构造方法
- FileInputStream(File file)
- FileInputStream(String name)
- FileInputStream的成员方法
- public int read():一次读取一个字节
- public int read(byte[] b):一次读取一个字节数组
- FileInputStream 类的构造方法
-
字节输入流读取数据的操作步骤:
- 第一步:创建字节输入流对象 ,并指定文件路径,不指定文件路径默认在项目路径。如果该路径没有该文件,便会报出找不到文件的错误
- 第二步:调用read()方法读取数据,并把数据显示在控制台
- 第三步:关闭流对象
- Demo代码示例
//读取数据//字节读取流
public class Demo02_IO_FileInputStream {
public static void main(String[] args) throws IOException {
//创建字节输入流对象,并且在 () 中填写文件名称,在创建对象时会在指定项目中已经存在的文件,准备读取文件中内容
FileInputStream fileInputStream = new FileInputStream("fos.txt");
/*
数据量小时候使用单个字节读取即可,假如我们要读取字节数比较大的文件的时候,我们就不能一次读取一个字节了,就要一次读取一个字节数组。
并且因为中文在utf-8编码中文占三个字节,GBK占两个字节,所以单个字符读取会乱码
*/
/* int in = 0;
// 读取,赋值,判断
while ((in = fileInputStream.read()) != -1){
System.out.print((char) in);
}*/
try {
//数据量大时,推荐使用下面这个方法,读取快且不会乱码
// 数组的长度一般是1024或者1024的整数倍
//注:此处数组长度设置为1024的原因,是因为 read(byte[] b)方法一次读取的是一整个字节数组,也就是一次读取1024个字节
byte[] bys = new byte[1024];
int len = 0;
while ((len = fileInputStream.read(bys)) != -1) {
System.out.print(new String(bys, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 释放资源
fileInputStream.close();
}
}
}
运行结果:
3、使用字节流复制数据
学习了文件操作类 File 类,以及上面的字节流读取和写入数据,接下来学习如何使用 File 类和字节流读取和写入数据实现数据的复制功能。
在实现复制功能时候,需要注意两点:
1、数据源:从哪里来
从 fos.txt 中读取数据,然后将读取到的数据存储到 FileInputStream 对象中。
2、目的地:到哪里去
通过 FileOutputStream 对象找到数据封装地,然后将从数据源读取出来的数据写入数据封装地。
Demo代码示例:
public class IO_CopyFile {
public static void main(String[] args) throws IOException{
IO_CopyFile cf = new IO_CopyFile ();
cf .copyFile();
}
//公共变量
FileInputStream copy = null;
FileOutputStream paste = null;
// 文件复制方法
public void copyFile() throws IOException{
try {
//指定封装数据源,该数据源需要是真实存在的,从该数据源中获取数据
copy = new FileInputStream("fos.txt");
//指定封装目的地,将从数据源获取到的数据存储在此文件中
paste = new FileOutputStream("copy.txt");
//使用这个方法可以将文件复制过去,但是效率会很慢,一个字节一个字节复制
/* int by = 0;
while ((by = copy.read()) != -1) {
paste.write(by);
}*/
//在实际开发中要是写复制文件的功能的话通常使用下面这个方法,一个复制1024个字节,会大大提升复制的效率
// 数组的长度一般是1024或者1024的整数倍
byte[] bys = new byte[1024];
int len = 0;
//copy对象调用read(),将copy对象所指定的文件中的字节数据内容读取出来,并存储在len变量中
while ((len = copy.read(bys)) != -1) {
//paste对象调用write方法,将len变量中的内容写入paste对象所指定的文件中
paste.write(bys, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 释放字节输出流和输入流资源
copy.close();
paste.close();
}
}
}
运行结果:
项目路径下会出现新创建的封装地文件–copy.txt
并且也成功的将文件内的数据复制到了封装地文件中。
4、字节缓冲流
在实现字节流复制数据的时候,可以发现字节一个一个读取和写入数据的效率要比一次读取和写入一个数组的效率要低。这是因为数组有着缓冲区的效果,所以使用数组读写数据会有效的提高效率。
java 本身在设计的时候,也考虑到了这样的设计思想(装饰设计模式),所以提供了字节缓冲区流。
这种类被称为:缓冲区类(高效类),其实和字节输入流和输出流的使用方法差不多,就是在原本的基础上提供了一个缓冲区。有效的提高我们在使用 IO 流时数据的流通效率。
- 缓冲区类(高效类)
-
字节缓冲输出流
- BufferedOutputStream
- 使用字节缓冲输入流写入数据
- Demo代码示例:
运行结果:public class BufferedOutputStreamDemo { public static void main(String[] args) throws IOException { // BufferedOutputStream(OutputStream out) // 创建字节缓冲输出流对象,将字节输出流对象放入缓冲区中 BufferedOutputStream bos = new BufferedOutputStream( new FileOutputStream("bos.txt")); // 写数据 bos.write("hello".getBytes()); // 释放资源 bos.close(); } }
- Demo代码示例:
- 使用字节缓冲输入流写入数据
- BufferedOutputStream
-
字节缓冲输入流
- BufferedInputStream
-
使用字节缓冲输入流读取数据
- Demo代码示例:
运行结果:public class BufferedInputStreamDemo { public static void main(String[] args) throws IOException { // BufferedInputStream(InputStream in) // 创建字节缓冲输入流对象,将字节输入流对象放入缓冲区中 BufferedInputStream bis = new BufferedInputStream( new FileInputStream( "bos.txt")); // 读取数据 byte[] bys = new byte[1024]; int len = 0; while ((len = bis.read(bys)) != -1) { // 将读取出来的数据打印在控制台 System.out.print(new String(bys, 0, len)); } // 释放资源 bis.close(); } }
- Demo代码示例:
-
- 使用字节缓冲流复制数据
- Demo代码示例:
public class BufferedCopy { public static void main(String[] args) { BufferedCopy bc = new BufferedCopy(); bc.bfCopy(); } public void bfCopy(){ BufferedInputStream bis = null; BufferedOutputStream bos = null; try { //数据源 bis = new BufferedInputStream( new FileInputStream( "bs.txt")); //封装地 bos = new BufferedOutputStream( new FileOutputStream("copyBs.txt")); byte[] bys = new byte[1024]; int len = 0; while ((len = bis.read(bys)) != -1) { bos.write(bys, 0, len); } } catch (IOException e) { e.printStackTrace(); } finally { try { bis.close(); } catch (IOException e) { e.printStackTrace(); } try { bos.close(); } catch (IOException e) { e.printStackTrace(); } } } }
运行结果: