JAVA_IO四大家族体系:
JAVA_IO流四大家族(1)
JAVA_IO流四大家族(2)
常识介绍
IO流,什么是IO?
I:Input
O:Output
通过IO可以完成硬盘文件的读写
IO流的分类:
一种方式是按照流的方向进行分类:
以内存为参照物,
往内存中去,叫做输入,或者叫做读,
从内存中出来,叫做输出,或者叫做写
另一种方式是按照读写数据方式不同进行分类:
有的流是按照字节的方式读取数据,一次读取一个字节byte,等同于一次读取8个二进制位,这种流是万能的,什么类型的文件都能读取。包括:文本文件,图片,声音文件,视频
假设文件file.txt,采用字节流是这样读的:
a中国bc张三fe
第一次读:一个字节,正好读到’a‘,
第二次读:一个字节,正好读完‘中’字符的一半
第三次读:一个字节,正好读到‘中’字符的另外一半
有的流是按照字符的方式读取数据的,一次读取一个字符,这种流是为了方便读取普通文本文件而存在的,这种流不能读取:图片,声音,视频等文件,只能读取纯文本文件,连word文件都没法读取。
假设文件file.txt,采用字符流是这样读的:
a中国bc张三fe
第一次读:'a’字符('a’字符在windows系统中占有一个字节)
第二次读:'中’字符('a’字符在windows系统中占有两个字节)
综上所述:流的分类
输入流,输出流
字节流,字符流
JAVA中主要研究:
怎么new流对象
调用流对象的哪个方法读,哪个方法写
四个家族首领
java.io.InputStream 字节输入流
java.io.OutputStream 字节输出流
java.io.Reader 字符输入流
java.io.Writer 字符输出流
四大家族首领都是抽象类(abstract class)
所有的流都实现了:java.io.Closeable接口,都是可关闭的,都有close()方法。
流毕竟是一个管道,这个是内存和硬盘之间的通道,用完之后一定要关闭,不然会耗费很多资源。养成好习惯,用完流一定要关闭
所有的输出流都实现了:
java.io.Flushable接口,都是可刷新的,都有flush()方法;养成好习惯,输出流在最终输出之后,一定要记得flush()刷新一下,这个刷新表示将通道/管道当中剩余未输出的数据强行输出完(清空管道)刷新的作用就是清空管道
注意:如果没有flush()可能会导致丢失数据;还有只有输出流有flush(),输入流并没有
注意:在java中只要“类名”以Stream结尾的都是字节流,以“Reader/Writer”结尾的都是字符流
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.DataOutputSteam
标准输出流:
java.io.PrintWriter
java.io.PrintStream
对象专属流:
java.io.ObjectInputStream
java.io.ObjectOutputStream
FileInputStream
read方法
调用一次read方法,文件指针会往后移动一位,即如下图
当执行到f下一个位置时,read返回值就为-1,那么这种read()读取实现的话,就可以用循环来实现
read方法1代码
/*
* 1.文件字节输出流,万能的,任何类型的文件都可以采用这个流来读
* 2.字节的方式,完成输入的操作,完成读的操作(硬盘--->内存)
* */
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class FileInputStreamTest01 {
public static void main(String[] args) {
//创建文件字节输入流对象
// 文件路径:(IDEA会自动把\编程\\,因为java中\代表转义)
FileInputStream fis=null;
try {
fis=new FileInputStream("G:\\test.txt");
//开始读
int readData =fis.read();//这个方法的返回值是:读取到的“字节”本身
System.out.print(readData+"\n");
readData =fis.read();//这个方法的返回值是:读取到的“字节”本身
System.out.print(readData+"\n");
readData =fis.read();//这个方法的返回值是:读取到的“字节”本身
System.out.print(readData+"\n");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//在finally语句块中确保流一定关闭
if(fis!=null){//避免空指针异常
//关闭流的前提是:流不是空
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
read方法1实现截图
read方法2代码
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class FileInputStreamTest02 {
public static void main(String[] args) {
FileInputStream fis=null;
try {
fis=new FileInputStream("G:\\test.txt");
while(true){
int readData=fis.read();
if(readData==-1){
break;
}
System.out.println(readData);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
改造后for循环
int readData=0;
while((readData=fis.read())!=-1){
System.out.println(readData);
}
read方法2实现截图
read方法3代码
IDEA默认的当前路径是哪里?
首先得搞懂这个问题,我们在src
下面创建一个tempfile
然后执行以下代码:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class FileInputStreamTest03 {
/*
*
* int read(byte[] b)
* 一次最多读取b.length个字节
* 减少硬盘和内存的交互,提高程序的执行效率
* 往byte数组当中读
* */
public static void main(String[] args) {
FileInputStream fis=null;
try {
//相对路径的话呢?相对路径一定是从当前所在的位置作为起点开始找
//IDEA默认的当前路径是哪里?工程project的根就是IDEA的默认当前路径
fis=new FileInputStream(
"tempfile");
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally {
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
毫无疑问,报错
找不到指定文件,很简单的原因,当前路径想错了
两个解决办法:
第一个 办法
先找到文件所在path
重点
IDEA默认的当前路径是哪里?工程project的根就是IDEA的默认当前路径
把tempfile
文件拷贝一份,放在工程project的根,也就是当前的上层目录
拷贝完成,然后再次执行上述代码
运行成功
第二个 办法
把如下代码
fis=new FileInputStream(
"tempfile");
变成
fis=new FileInputStream(
"src//tempfile");
执行结果如下
操作过程(如何看长度)
开始读,采用byte
数组,一次读取多个字节,最多读取“数组.length”个字节
byte []bytes=new byte [4];//准备一个4个长度的数组,一次最多读取4个字节
第一次调用read(bytes)
如下图:
int readCount= fis.read(bytes);
这个方法的返回值是:读取到的字节数量(不是字节本身),数据已经放在了bytes
数组中去
第二次调用read(bytes)
如下图:
这次读取到了两个字节
readCount= fis.read(bytes);
System.out.println(readCount);//第二次只能读到2个字节
第三次调用read(bytes)
:
读不到任何数据返回-1
readCount= fis.read(bytes);//第三次1个字节都没有读取到,返回-1
System.out.println(readCount);//-1
操作过程(如何看读取出的数据)
//这个方法的返回值是:读取到的字节数量(不是字节本身)
int readCount= fis.read(bytes);
System.out.println(readCount);//第一次读到了4个字节
System.out.println(new String(bytes));
readCount= fis.read(bytes);
System.out.println(new String(bytes));
// System.out.println(readCount);//第二次只能读到2个字节
第二次只读取两个字节,然后它把读取到的5和6放在1和2位置处,但是原来数组中3和4还依然存在,这也就符合我们下图所表示的
操作过程注意点
问题来了,我们应该是读取了多少个,就写多少个,(不应该全部转换)而不是写数组的全部进入String中,应该用如下形式
//开始读,采用byte数组,一次读取多个字节,最多读取“数组.length”个字节
byte []bytes=new byte [4];//准备一个4个长度的数组,一次最多读取4个字节
//这个方法的返回值是:读取到的字节数量(不是字节本身)
int readCount= fis.read(bytes);
System.out.println(readCount);//第一次读到了4个字节
System.out.println(new String(bytes,0,readCount));
readCount= fis.read(bytes);
System.out.println(new String(bytes,0,readCount));
// System.out.println(readCount);//第二次只能读到2个字节
readCount= fis.read(bytes);//第三次1个字节都没有读取到,返回-1
总结实现代码
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class FileInputStreamTest04 {
public static void main(String[] args) {
FileInputStream fis=null;
try {
fis=new FileInputStream("src//tempfile");
//准备一个byte数组
byte[]bytes=new byte[4];
int readCount=0;
while(true){
readCount=fis.read(bytes);
if(readCount==-1){
break;
}
System.out.print(new String(bytes,0,readCount));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
改版后的while循环
int readCount1=0;
while((readCount1=fis.read(bytes))!=-1){
System.out.print(new String(bytes,0,readCount1));
}
available方法
int available()
返回流当中剩余的没有读到的字节数量
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class FileInputStreamTest05 {
public static void main(String[] args) {
FileInputStream fis=null;
try {
fis=new FileInputStream("");
System.out.println("总字节数量"+fis.available());
//读取1个字节
int readByte=fis.read();
//还剩下可以读的字节数量是5;
System.out.println("剩下多少字节没有读:"+fis.available()+"字节");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
作用如下:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class FileInputStreamTest05 {
public static void main(String[] args) {
FileInputStream fis=null;
try {
fis=new FileInputStream("src//tempfile");
System.out.println("总字节数量"+fis.available());
//这个方法有什么用?
byte []bytes=new byte[fis.available()];//这种方式不太适合太大的文件,因为byte数组不能太大
//不需要循环了
//直接读一次就行了
int readCount=fis.read(bytes);
System.out.print(new String(bytes));//一次到位
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
注意:
这种方式不太适合太大的文件,因为byte数组不能太大
skip方法
跳过几个字节不读取
long skip (long n)
实现代码
public class FileInputStreamTest05 {
public static void main(String[] args) {
FileInputStream fis=null;
try {
fis=new FileInputStream("src//tempfile");
fis.skip(3);
System.out.print(fis.read());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
字符4的ASCII码值是52
FileOutputStream
实现代码1(清空再写入)
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStreamTest01 {
/*
* 文件字节输出流,负责写
* 从内存到硬盘
* */
public static void main(String[] args) {
FileOutputStream fos=null;
try {
fos=new FileOutputStream("myfile");
//开始写
byte[]bytes={97,98,99,100};
fos.write(bytes);
fos.write(bytes,0,2);//再写出ab
//写完之后,最后一定要刷新
fos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fos!=null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
注意点
myfile
文件不存在时会自动新建- 这种方式谨慎使用,这种方式会将原文件清空,然后重新写入
实现代码2(以追加的方式)
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStreamTest01 {
/*
* 文件字节输出流,负责写
* 从内存到硬盘
* */
public static void main(String[] args) {
FileOutputStream fos=null;
try {
//myfile文件不存在时会自动新建
//这种方式谨慎使用,这种方式会将原文件清空,然后重新写入
fos=new FileOutputStream("myfile",true);
//开始写
byte[]bytes={97,98,99,100};
fos.write(bytes);
fos.write(bytes,0,2);//再写出ab
//写完之后,最后一定要刷新
fos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fos!=null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
注意点
myfile
文件不存在时会自动新建- 以追加的方式在文件末尾写入,不会清空原文件内容
实现截图
执行前:
执行后:
如何写入一个String字符串
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStreamTest01 {
/*
* 文件字节输出流,负责写
* 从内存到硬盘
* */
public static void main(String[] args) {
FileOutputStream fos=null;
try {
//myfile文件不存在时会自动新建
//这种方式谨慎使用,这种方式会将原文件清空,然后重新写入
fos=new FileOutputStream("myfile",true);
String s="我是一个中国人,我自豪";
byte[] bytes3=s.getBytes();
fos.write(bytes3);
//写完之后,最后一定要刷新
fos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fos!=null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}