1.研究IO流,我们主要研究什么?
- 怎么new流对象。
- 调用流对象的哪个方法是读,哪个方法是写。
因为:java中所有的流都是在:java.io.*;下。
2.什么是IO流?
I : Input
O : Output
通过IO可以完成硬盘文件的读和写。+
3.IO流的分类?
- 在java中只要“类名”以Stream结尾的都是 字节流。
- 以“Reader/Writer”结尾的都是 字符流。
3.1.按照流的方向进行分类:以内存为参照
- 输入流:往内存中去,叫做输入(Input)。或者叫做读(Read)。
- 输出流:从内存中出来,叫做输出(Output)。或者叫做写(Write)。
3.2.按照读取数据方式不同进行分类:
- 字节流:按照字节的方式读取数据,一次读取1个字节byte,等同于一次读取8个二进制位。
这种流是万能的,什么类型的文件都可以读取。包括:文本文件,图片,声音文件,视频文件等…
假设文件file1.txt,采用字节流的话是这样读的:
a中国bc张三fe
第一次读:一个字节,正好读到'a'
第二次读:一个字节,正好读到'中'字符的一半。
第三次读:一个字节,正好读到'中'字符的另外一半。
- 字符流:一次读取一个字符。
这种流是为了方便读取普通文本文件而存在的,这种流不能读取:图片、声音、视频等文件。只能读取纯文本文件,连word文件都无法读取。
假设文件file1.txt,采用字符流的话是这样读的:
a中国bc张三fe
第一次读:'a'字符('a'字符在windows系统中占用1个字节。)
第二次读:'中'字符('中'字符在windows系统中占用2个字节。)
4.java IO流这块有四大家族
- 四大家族的首领都是抽象类。(abstract class)
java.io.InputStream 字节输入流
java.io.OutputStream 字节输出流
java.io.Reader 字符输入流
java.io.Writer 字符输出流
4.1.所有的流都实现了:
- java.io.Closeable接口,都是可关闭的,都有close()方法。
流毕竟是一个管道,这个是内存和硬盘之间的通道,用完之后一定要关闭,不然会耗费(占用)很多资源。养成好习惯,用完流一定要关闭。
4.2.输出流都实现了: - java.io.Flushable接口,都是可刷新的,都有flush()方法。
养成一个好习惯,输出流在最终输出之后,一定要记得flush()刷新一下。这个刷新表示将通道/管道当中剩余未输出的数据强行输出完(清空管道!)刷新的作用就是清空管道。 - ★★★★★注意:如果没有flush()可能会导致丢失数据。
5.java.io包下需要掌握的流有16个:
- 文件专属:
java.io.FileInputStream(掌握)
java.io.FileOutputStream(掌握)
java.io.FileReader
java.io.FileWriter - 转换流:(将字节流转换成字符流)
java.io.InputStreamReader
java.io.OutputStreamWriter - 缓冲流专属:
java.io.BufferedReader
java.io.BufferedWriter
java.io.BufferedInputStream
java.io.BufferedOutputStream - 数据流专属:
java.io.DataInputStream
java.io.DataOutputStream - 标准输出流:
java.io.PrintWriter
java.io.PrintStream(掌握) - 对象专属流:
java.io.ObjectInputStream(掌握)
java.io.ObjectOutputStream(掌握)
6.字节流,案例分析
- xx.read();文件的数据都被读取完了,返回-1。
6.1.file = new FileInputStream(“IOtxt.txt”);
目标文件:
执行结果:
分析:
1.tempdata=file.read();返回的tempdata是字节数据(eg:a返回97)
2. file.close();在try…catch之后要在finally,关闭流通道。
public class IOTest {
public static void main(String[] args) throws IOException {
FileInputStream file =null;//先创建FileInputStream对象
try {
/**读取字节流*****/
// file = new FileInputStream("D:\\JavaSEadvance\\IO\\IOtxt.txt");
file = new FileInputStream("IOtxt.txt");//相对路径,默认位置是project根目录
int tempdata=0;
while (tempdata!=-1){
tempdata=file.read(); /**需要设置,处理异常**/
System.out.println(tempdata);
}
}
catch (FileNotFoundException e){ /***捕捉异常***/
e.printStackTrace();
}finally {
if (file!=null){ /****如果流没关,则关闭 流******/
try{
file.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
}
6.2.不使用file.available(),向固定长度byte数组中存入内容
目标文件:
执行结果:
分析:
- 1.byte[] bytes2=new byte[5];
int dataNumber2 = file.read(bytes2);
每次只读出5个字节,所以abcdefh不能一次输出,一次最多输出5个。 - 2.System.out.println(new String(bytes2, 0, dataNumber2));
本次读出多少,就输出多少。因为最后一次读出三个,如果输出整个bytes2,则结果是:fghde,但正确结果是:fgh。所以需要dataNumber2进行数组转换长度限制。
/***向固定长度byte数组中存入内容***/
class IOtest02{
public static void main(String[] args) {
FileInputStream file=null;
try {
file=new FileInputStream("D:\\JavaSEadvance\\IO\\src\\IOtxt.txt");
/***不使用file.available(),使用固定数组*****/
byte[] bytes2=new byte[5];
while (true) {
int dataNumber2 = file.read(bytes2);//这个方法返回的是读取字节的数量,而不是字节本身
//bytes2才是字节本身
if (dataNumber2==-1)
break;
System.out.println(new String(bytes2, 0, dataNumber2));//只输出本次读取到的“dataNumber2”个字节转成的字符串
}
}catch (FileNotFoundException e){
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(file!=null) { //关闭 流
try {
file.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
}
6.3.file.available()的数值就是file文件内所有字节的个数
file.available()长度定义的byte数组中读取内容,数组可一次取出file文件所有字节
目标文件:
执行结果:
分析:
- byte[] bytes=new byte[file.available()];
new出的数组长度为file.available(),可以一次放下file文件中的所有字节。
/***向file.available()的长度定义的byte数组中读取内容***/
class IOtest03{
public static void main(String[] args) {
FileInputStream file=null;
try {
file=new FileInputStream("IOtxt.txt");
/***使用file.available(),数组可一次取出全部文件字节*****/
//file.available(),可以得到要读取文件的字节长度,能创建一个数组,直接存整个文件,
//file.available() 不适用于大文件,因为byte数组不能太大
byte[] bytes=new byte[file.available()];
int dataNumber= file.read(bytes);//这个方法返回的dataNumber是读取字节的数量,而不是字节本身
//bytes才是字节本身
System.out.println("本次读取字节长度:"+dataNumber);
String str = new String(bytes);//字节数组全部转成字符串
System.out.println(str);
}catch (FileNotFoundException e){
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(file!=null) { //关闭 流
try {
file.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
}
6.4.测试skip,跳过几个字节不读
目标文件:
file.skip(5);//跳过5个字节不读
执行结果:
/***测试skip,跳过几个字节不读***/
class IOtest04{
public static void main(String[] args) {
FileInputStream file=null;
try {
file=new FileInputStream("IOtxt.txt");
file.skip(5);//跳过5个字节不读
/***使用file.available(),一个数组取出全部文件字节*****/
//file.available(),可以得到要读取文件的字节长度,能创建一个数组,直接存整个文件,
//file.available() 不适用于大文件,因为byte数组不能太大
byte[] bytes=new byte[file.available()];
int dataNumber= file.read(bytes);//这个方法返回的是读取字节的数量,而不是字节本身
System.out.println(dataNumber);
String str = new String(bytes);//字节数组全部转成字符串
System.out.println(str);
}catch (FileNotFoundException e){
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(file!=null) { //关闭 流
try {
file.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
}
6.5.Fileout测试,从内存向硬盘输出数据
fileOut=new FileOutputStream("myfile",true);
//true:表示会在原文件,末尾,添加字节
//false:表示会清空原文件,重新写入
输出数据:
byte[] bytes={100,101,102,103,104,105,106};
执行1次代码的结果:
执行2次代码的结果:(在文件末尾,再加入数据)
分析:
1.fileOut.write(bytes);//执行写入
2.fileOut.flush();//用完输出流,要清空管道,否则可能会丢失数据
/***Fileout测试
* //true:表示会在原文件末尾添加字节
* //false:表示会清空原文件,重新写入
* fileOut=new FileOutputStream("myfile",true);
* ****/
class IOtest05{
public static void main(String[] args) {
FileOutputStream fileOut=null;
try {
//"myfile"文件名不存在时,会自动创建
//这种方式谨慎使用,因为它会将原文件清空,然后重新写入
//fileOut=new FileOutputStream("myfile");
//true:表示会在原文件末尾添加字节
//false:表示会清空原文件,重新写入
fileOut=new FileOutputStream("myfile",true);
byte[] bytes={100,101,102,103,104,105,106};
fileOut.write(bytes);
fileOut.flush();//用完输出流,要清空管道,否则可能会丢失数据
}catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileOut!=null){ //关闭 IO流
try {
fileOut.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
6.6.测试文件的copy(可copy各种文件)
分析:
1.创建一个输入流对象
- fileIn=new FileInputStream(“D:\迅雷下载\星际穿越.mp4”);
2.创建一个输出流对象
- fileOut= new FileOutputStream(“D:\星际穿越.mp4”);
3.byte[] bytes=new byte[1024*1024];//每次传输1MB
- 设置每次传输的数据大小
class IOtestFileCopy{
public static void main(String[] args) {
FileInputStream fileIn = null;
FileOutputStream fileOut= null;
try {
//创建一个输入流对象
fileIn=new FileInputStream("D:\\迅雷下载\\星际穿越.mp4");
//创建一个输出流对象
fileOut= new FileOutputStream("D:\\星际穿越.mp4");
//最核心的一边读,一边写
byte[] bytes=new byte[1024*1024];//每次传输1MB
int tempData=0;
while ((tempData=fileIn.read(bytes))!=-1){
fileOut.write(bytes,0,tempData);
}
//刷新,输出流最后要刷新
fileOut.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
//fileIn、fileOut需要分开try,防止一起try的时候,其中一个出现异常,另一个关闭不了
// if (fileIn!=null || fileOut!=null){
// try {
// fileIn.close();
// fileOut.close();
// } catch (IOException e) {
// e.printStackTrace();
// }
// }
//fileIn、fileOut需要分开try,防止一起try的时候,其中一个出现异常,另一个关闭不了
if (fileIn!=null){
try {
fileIn.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fileOut!=null){
try {
fileOut.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
6.7.测试普通文本文件的复制(连word也不行)
分析:
1.FileReader()、FileWriter(),只能读取字符型数据
class IOtestTxtCopy{
public static void main(String[] args) {
FileReader reader = null;
FileWriter writer = null;
try {
reader = new FileReader("test.txt"); //创建一个读出对象
writer = new FileWriter("test02"); //创建一个写入对象
char[] chars = new char[4]; //字符型数据,每次传输4个字符型数据
int tempData=0;
while ((tempData=reader.read(chars))!=-1){ //当数据还没读完时
writer.write(chars,0,tempData); //把每次读出的数据,写入另一个文件
}
writer.flush();//输出流刷新,防止丢失数据
} catch (FileNotFoundException e) { //捕捉输入流异常
e.printStackTrace();
} catch (IOException e) { //捕捉输出流异常
e.printStackTrace();
}
}
}