24.2.字节流
2.1.IO流概述和介绍
IO流述
- IO:输入/输出(Input/Output)
- 流:是一种抽象概念,是对数据传输的总称。也就是说数据在设备间的传输称为流,流的本质是数据传输
- IO流就是用来处理设备间数据传输问题的
- 常见的应用:文件复制;文件上传;文件下载
IO流的分类
-
按照数据的流向
- 输入流:读数据
- 输出流:写数据
-
按照数据类型来分
字节流
字节输入流 ; 字节输出流
字符流
字符输入流 ; 字符输出流
一般来说,我们说IO流的分类是按照数据类型来分的那么这两种流都在什么情况下使用呢?
如果数据通过Window自带的记事本软件打开,我们还可以读懂里面的内容,就使用字符流,否则使用字节流。如果你不知道该使用哪种类型的流,就使用字节流
2.2 字节流写数据
字节流抽象基类
- lnputStream:这个抽象类是表示字节输入流的所有类的超类
- OutputStream:这个抽象类是表示字节输出流的所有类的超类
- 子类名特点:子类名称都是以其父类名作为子类名的后缀
FileOutputStream:文件输出流用于将数据写入File
- FileOutputStream(String name):创建文件输出流以指定的名称写入文件
使用字节输出流写数据的步骤:
- 创建字节输出流对象(调用系统功能创建了文件,创建字节输出流对象,让字节输出流对象指向文件)
- 调用字节输出流对象的写数据方法
- 释放资源(关闭此文件输出流并释放与此流相关联的任何系统资源)
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStreamDemo01 {
public static void main(String[] args) throws IOException {
//创建字节输出流对象
//FileOutputStream(Stringname):创建文件输出流以指定的名称写入文件
FileOutputStream fos = new FileOutputStream(".\\fos.txt");
/*
做了三件事情;
A:调用系统功能创建了文件
B:创建了字节输出流对象
c:让字节输出流对象指向创建好的文件
*/
// void write (int b),将指定的字节写入此文件输出流
fos.write(97);
// fos.write(57);
// fos.write(55);
// 最后都要释放资源
//void close ():关闭此文件输出流并释放与此流相关联的任何系统资源。
fos.close();
}
}
2.3.字节流写数据的三种方式
方法名 | 说明 |
---|---|
void write(int b) | 将指定的字节写入此文件输出流一次写一个字节数据 |
void write(byte[] b) | 将b.length字节丛指定的字节数组写入此文件输出流一次写一个字节数组数据 |
void write(byte[] b,int off,int len) | 将len字节从指定的字节数组开始,从偏移量off开始写入此文件输出流一次写一个字节数组的部分数据 |
构造方法;
FileOutputStream(String name):创建文件输出流以指定的名称写入文件
FileOutputStream(file file):创建文件输出流以写入由指定的File对象表示的文件
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStreamDemo02 {
public static void main(String[] args) throws IOException {
//FileOutputStream(String name):创建文件输出流以指定的名称写入文件, 一般写这个方便
FileOutputStream fos = new FileOutputStream(".\\fos.txt");
//new File(name)自动封装了
// FileOutputStream fos = new FileOutputStream(new File(".\\fos.txt"));
//FileOutputStream(file file):创建文件输出流以写入由指定的File对象表示的文件
// FileOutputStream fos2 = new FileOutputStream(new File(".\\fos.txt"));
// void write(int b)将指定的字节写入此文件输出流一次写一个字节数据
/*
fos.write(97);
fos.write(98);
fos.write(99);
fos.write(100);
fos.write(101);*/
//void write(byte[] b)将b.length字节丛指定的字节数组写入此文件输出流一次写一个字节数组数据
/// byte[] bys = {97,98,99,100,101,102};
//byte[] getBytes ():返回字符串对应的字节数组
byte[] bys = "abcdefg".getBytes();
// fos.write(bys);
/// void write(byte[] b,int off,int len)将len字节从指定的字节数组开始,从偏移量off开始写入此文件输出流一次写一个字节数组的部分数据
fos.write(bys, 1, 3);
// 释放资源
fos.close();
}
}
2.4.字节流写数据的两个小问题
1.字节流写数据如何实现换行
window: \r\n
linux: \n
mac: \r
2.字节流写数据如何实现追加写入
-
public FileOutputStream (String name , boolean append)
-
创建文件输出流以指定的名称写入文件。如果第二个参数为true ,则字节将写入文件的末尾而不是开头
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStreamDemo03 {
public static void main(String[] args) throws IOException {
//创建字节流输出对象
// FileOutputStream fos = new FileOutputStream(".\\fos.txt");
FileOutputStream fos = new FileOutputStream(".\\fos.txt",true);
//写数据
for (int i = 0; i < 10; i++){
fos.write("hello".getBytes());
fos.write("\r\n".getBytes());
}
//释放资源
fos.close();
}
}
2.5.字节流写数据加异常处理
==finally:==在异常处理时提供finally块来执行所有清除操作。比如说IO流中的释放资源
特点:被finally控制的语句一定会执行,除非JVM退出
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStreamDemo04 {
public static void main(String[] args) throws FileNotFoundException {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(".\\fos.txt");
fos.write("hello".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null)
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
2.6.字节流读数据(一次读一个字节数据)
FilelnputStream:从文件系统中的文件获取输入字节
-
FileInputStream(String name):
通过打开与实际文件的连接来创建一个
FileInputStream,该文件由文件系统中的路径名
name 命名。read方法包括:
-
read(),此方法一个字节一个字节的读取,从输入流中读取数据的下一个字节。返回 0 到 255 范围内的 int 字节值。如果因为已经到达流末尾而没有可用的字节,则返回值 -1 。
-
read (byte[] b),此方法按b进行读取,如果文件总共读取的byte长度是46,b长度为10,则读取4次,每次读取10个字节,最后一次读取6个字节。以整数形式返回实际读取的字节数。
-
read (byte[] b,int off,int len) 方法, 将输入流中最多 len 个数据字节读入 byte 数组。尝试读取 len 个字节,但读取的字节也可能小于该值。以整数形式返回实际读取的字节数。
write方法包括:(参照read方法)
-
write()
-
write (byte[] b) 在这里,和read方法不同的是,如果byte长度是46,则输出5次,每次读取10个字节,最后一次只有6个字节,却多出了4个字节,而采用第三种方法就可以避免你多余输出,占了内存。
-
write (byte[] b,int off,int len)
-
/*
需求:把文件fos.txt中的内容读取出来在控制台输出
使用字节输入流读数据的步骤 :
① 创建字节输入流对象
② 调用字节输入流对象的读数据方法
③ 释放资源
*/
import java.io.FileInputStream;
import java.io.IOException;
public class FileIntputStreamDemo01 {
public static void main(String[] args) throws IOException {
//创建字节输入流对象
//FileInputStream(String name)
FileInputStream fis = new FileInputStream("E:\\javastudent\\fos.txt");
// 调用字节输入流对象的读数据方法
// int read() 从该输入流读取一个字节的数据。
/*
//第一次读取数据
int by = fis.read();
System.out.println(by);
System.out.println((char) by);
System.out.println("-----");
//第二次读取数据
by = fis.read();
System.out.println(by);
System.out.println((char) by);
System.out.println("-----");
//再多读取两次
by = fis.read();
System.out.println(by);
by = fis.read();
System.out.println(by);
*/
/* int by = fis.read();
while (by != -1) {
System.out.print((char) by);
by = fis.read();
}*/
// 优化上面的程序
int by;
/*
fis.read( ):读数据
by=fis.read():把读取到的数据赋值给by
by != -1:判断读取到的数据是否是-1*/
while ((by = fis.read()) != -1) {
System.out.print((char) by);
}
// 释放资源
fis.close();
}
}
/*
hello
world
*/
2.7.案例:复制文本文件
需求:把“E:\\窗里窗外.txt”复制到模块目录下的“窗里窗外.txt"
分析:
①复制文本文件,其实就把文本文件的内容从一个文件中读取出来(数据源),然后写入到另一个文件中(目的地)
数据源:
E:\\窗里窗外.txt —读数据— InputStream —FilelnputStream
目的地:
窗里窗外.txt—写数据— OutputStream -----FileOutputStream
思路:
①根据数据源创建字节输入流对象
②根据目的地创建字节输出流对象
③读写数据,复制文本文件(一次读取一个字节,一次写入一个字节)
④释放资源
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyTxtDemo {
public static void main(String[] args) throws IOException {
//根据数据源创建字节输入流对象
FileInputStream fis = new FileInputStream("E:\\窗里窗外.txt");
//根据目的地创建字节输出流对象
FileOutputStream fos = new FileOutputStream("窗里窗外.txt");
//读写数据,复制文本文件(一次读取一个字节,一次写入一个字节)
int by;
while ((by=fis.read())!=-1){
fos.write(by);
}
//释放资源
fos.close();
fis.close();
}
}
2.8字节流读数据(一次读一个字节数组数据)
需求:把文件fos.txt中的内容读取出来在控制台输出
使用字节输入流读数据的步骤:
①创建字节输入流对象
②调用字节输入流对象的读数据方法
③释放资源
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.String;
public class FileInputStreamDemo02 {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("fos.txt");
//调用字节输入流对象的读数据方法
//int read (byte[] b),从该输入流读取最多b.length个字节的数据到一个字节数组
// byte[] bys =new byte[5];
//
// //第一次读取数据
// int len =fis.read(bys);
// System.out.println(len);
// //String (byte[] bytes)
// System.out.println(new String(bys,0,len));
//
// //第二次读取数据
// len =fis.read(bys);
// System.out.println(len);
// System.out.println(new String(bys,0,len));
//
// //第三次读取数据
// len =fis.read(bys);
// System.out.println(len);
//String (byte[] bytes, int offset, int length)
// System.out.println(new String(bys,0,len));
byte[] bys = new byte[1024];//1024及其整数倍
int len;
while ((len = fis.read(bys)) != -1) {
System.out.println(new String(bys,0,len));
}
//释放资源
fis.close();
}
}
/*
hello
world
*/
2.9.案例复制图片
需求:把“E:\litcastlImn.jpg”复制到模块目录下的“mn.jpg"
思路:
①根据数据源创建字节输入流对象
②根据目的地创建字节输出流对象
③读写数据,复制图片(一次读取一个字节数组,一次写入一个字节数组)
④释放资源
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyJpgDemo {
public static void main(String[] args) throws IOException {
//根据数据源创建字节输入流对象
FileInputStream fis = new FileInputStream("D:\\Backup\\我的文档\\My Pictures\\Saved Pictures\\mn.jpg");
//根据目的地创建字节输出流对象
FileOutputStream fos = new FileOutputStream("mn.jpg");
//读取数据,复制图片(一次读取一个字节数组,一次写入一个字节数组)
byte[] bys = new byte[1024];
int len;
while ((len = fis.read(bys)) != -1) {
fos.write(bys, 0, len);
}
//释放资源
fos.close();
fis.close();
}
}
2.10.字节缓冲流
字节缓冲流:
-
BufferOutputStream: 该类实现缓冲输出流。通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用
-
BufferedInputStream: 创建Bufferedlnputstream将创建一个内部缓冲区数组。当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节
构造方法:
- 字节缓冲输出流: BufferedOutputStream(OutputStream out)
- 字节缓冲输入流: BufferedInputStream(InputStream in)
为什么构造方法需要的是字节流,而不是具体的文件或者路径呢?
- 字节缓冲流仅仅提供缓冲区,而真正的读写数据还得依靠基本的字节流对象进行操作
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
public class BufferStreamDemo {
public static void main(String[] args) throws IOException {
// 字节缓冲输出流: BufferedOutputStream(OutputStream out)
/* FileOutputStream fos = new FileOutputStream("bos.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);*/
/*
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("bos.txt"));
//写数据
bos.write("hello\r\n".getBytes());
bos.write("world\r\n".getBytes());
bos.close();*/
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("bos.txt"));
//读数据
//一次读取一个字节数据
/* int by;
while ((by=bis.read())!=-1){
System.out.print((char) by);
}
System.out.println("-----");
bis.close();*/
// 一次读取一个字节数据的数据
byte[] bys = new byte[1024];
int len;
while ((len=bis.read(bys))!=-1){
System.out.println(new String(bys,0,len));
}
bis.close();
}
}
2.11.复制视频(改成了gif图)
需求:把“E:字节流复制图片.avi”复制到模块目录下的“字节流复制图片.aviT
思路:
①根据数据源创建字节输入流对象
②根据目的地创建字节输出流对象
③读写数据,复制视频
④释放资源
1.基本字节流一依读写一个字节
/*
四种方式实现复制视频,并记录每种方式复制视频的时间
1.基本字节流一依读写一个字节 共耗时: 4986毫秒
2.基本字节流一次读写一个字节数组 共耗时: 5253毫秒
3.字节缓冲流一次读写一个字节 共耗时: 54毫秒
4.字节缓冲流一次读写—个字节数组 共耗时: 5毫秒
*/
import java.io.*;
public class CopyVideo {
public static void main(String[] args) throws IOException {
//记录开始时间
long startTime = System.currentTimeMillis();
//复制视频
// method1();
// method2();
// method3();
method4();
//记录结束时间
long endTime = System.currentTimeMillis();
System.out.println("共耗时: " + (endTime - startTime) + "毫秒");
}
// 4.字节缓冲流一次读写—个字节数组
public static void method4() throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\Backup\\我的文档\\My Pictures\\Saved Pictures\\上个图很难吗.gif"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("上个图很难吗.gif"));
byte[] bys = new byte[1024];
int len;
while ((len=bis.read(bys))!=-1){
bos.write(bys,0,len);
}
bos.close();
bis.close();
}
// 3.字节缓冲流一次读写一个字节
public static void method3() throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\Backup\\我的文档\\My Pictures\\Saved Pictures\\上个图很难吗.gif"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("上个图很难吗.gif"));
int by;
while ((by = bis.read()) != -1) {
bos.write(by);
}
bos.close();
bis.close();
}
public static void method2() throws IOException {
FileInputStream fis = new FileInputStream("D:\\Backup\\我的文档\\My Pictures\\Saved Pictures\\上个图很难吗.gif");
FileOutputStream fos = new FileOutputStream("上个图很难吗.gif");
byte[] bys = new byte[1024];
int len;
while ((len = fis.read()) != -1) {
fos.write(bys, 0, len);
}
fos.close();
fis.close();
}
public static void method1() throws IOException {
FileInputStream fis = new FileInputStream("D:\\Backup\\我的文档\\My Pictures\\Saved Pictures\\上个图很难吗.gif");
FileOutputStream fos = new FileOutputStream("上个图很难吗.gif");
int by;
while ((by = fis.read()) != -1) {
fos.write(by);
}
fos.close();
fis.close();
}
}