一、概念
文件在程序中是以流的形式来操作的。
流:是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两个存储位置之间的传输称为流。流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。
二、分类
1、按照流向划分:输入流、输出流
以内存为参照:
输入流:从文件流向内存
输出流:从内存流向文件
2、按照传输单位划分:字节流、字符流
字节流:可以用于读写二进制文件及任何类型文件。
字符流:可以用于读写文本文件。
三、字节流VS字符流的区别
字符流的由来: 因为数据编码的不同,从而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表。
区别:
1、读写单位不同:字节流以字节(1 byte,1byte=8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
2、处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。
3、缓存。字节流在操作的时候本身是不会用到缓冲区的,是文件本身的直接操作的;而字符流在操作的时候下后是会用到缓冲区的,是通过缓冲区来操作文件。
总结:优先选用字节流。因为硬盘上的所有文件都是以字节的形式进行传输或者保存的,包括图片等内容。字符只是在内存中才会形成的,所以在开发中,字节流使用广泛。
四、具体的案例讲解
案例0
功能:1、创建文件夹、文件 2、遍历文件夹下面的所有文件
- public class Test1 {
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- //创建新文件夹对象ff
- File f1 = new File("D:/FF");
- //如果存在
- if(f1.isDirectory()){
- System.out.println("已经存在该文件夹!");
- //将文件夹下面的所有文件 组成数组
- File lists[] = f1.listFiles();
- System.out.println("ff文件夹下面有"+lists.length+"个文件");
- //遍历,取出所有的文件名称
- for(int i=0;i<lists.length;i++){
- System.out.println("文件名 :" +lists[i].getName());
- }
- }else {
- //如果不存在该文件夹,则输出
- System.out.println("该文件夹不存在!");
- f1.mkdir();
- }
- //在该文件夹下面创建 新的文件
- File f2 = new File("d:\\ff\\psp.txt");
- //如果存在在文件
- if(f2.exists()){
- System.out.println("已经存在该文件");
- }else{
- try {
- f2.createNewFile();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- }
功能:从数据源中读取数据到内存(FileInputStream的使用)
- /**
- * 功能:从数据源中读取数据到内存
- */
- public class Test {
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- File f1 = new File("d:\\ff\\test.txt");
- FileInputStream fis=null;
- try {
- fis = new FileInputStream(f1);
- byte[] bytes= new byte[1024];
- //得到实际读取的长度
- int n=0;
- //循环读取
- while((n=fis.read(bytes))!=-1){
- String s = new String(bytes,0,n);
- System.out.print(s);
- }
- } catch (Exception e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }finally{
- //最后一定要关闭文件流
- try {
- fis.close();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- }
功能:演示FileOutputStream,从内存中读取数据到数据源
- public class Test {
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- File f1 = new File("d:\\ff\\test.txt");
- FileOutputStream fos = null;
- try {
- fos = new FileOutputStream(f1);
- String s="我是曾可达,我是曾可达!\r\n";
- String s2="听到请回答!";
- byte bytes[] = new byte[1024];
- fos.write(s.getBytes());
- fos.write(s2.getBytes());
- } catch (Exception e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }finally{
- try {
- fos.close();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- }
案例3
功能:演示FileInputStream ,FileOutputStream ;将图片从C盘拷贝到D盘
- public class Test {
- public static void main(String[] args) {
- //定义输入流
- FileInputStream fis =null;
- //定义输出流
- FileOutputStream fos=null;
- try {
- fis = new FileInputStream("c:\\boy.jpg");
- fos = new FileOutputStream("d:\\boy.jpg");
- //读取
- byte [] bytes = new byte[1024];
- int n=0;
- while((n=fis.read(bytes))!=-1){
- fos.write(bytes, 0, n);
- }
- } catch (Exception e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }finally{
- try {
- fis.close();
- fos.close();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- }
一、超类:
字节流: InputStream(读入流) OutputStream(写出流)字符流: Reader(字符 读入流) Writer (字符写出流)
二、文件操作流
字节流: FileInputStream ,FileOutputStream
字符流: FileReader, FileWriter(用法与字节流基本相同,不写)
//1.指定要读 的文件目录及名称
File file =new File("文件路径");
//2.创建文件读入流对象
FileInputStream fis =new FileInputStream(file);
//3.定义结束标志,可用字节数组读取
int i =0 ;
while((i = fis.read())!=-1){
//i 就是从文件中读取的字节,读完后返回-1
}
//4.关闭流
fis.close();
//5.处理异常
//1.指定要写到的文件目录及名称
File file =new File("文件路径");
//2.创建文件读入流对象
FileOutputStream fos =new FileOutputStream(file);
//3.定义结束标志
fos.write(要写出的字节或者字节数组);
//4.刷新和关闭流
fos.flush();
fos.close();
//5.处理异常
三、缓冲流:
字节缓冲流: BufferedInputStream,BufferedOutputStream
字符缓冲流:BufferedReader ,BufferedWriter
缓冲流是对流的操作的功能的加强,提高了数据的读写效率。既然缓冲流是对流的功能和读写效率的加强和提高,所以在创建缓冲流的对象时应该要传入要加强的流对象。
//1.指定要读 的文件目录及名称
File file =new File("文件路径");
//2.创建文件读入流对象
FileInputStream fis =new FileInputStream(file);
//3.创建缓冲流对象加强fis功能
BufferedInputStream bis =new BufferedInputStream(fis);
//4.定义结束标志,可用字节数组读取
int i =0 ;
while((i = bis.read())!=-1){
//i 就是从文件中读取的字节,读完后返回-1
}
//5.关闭流
bis.close();
//6.处理异常
//1.指定要写到的文件目录及名称
File file =new File("文件路径");
//2.创建文件读入流对象
FileOutputStream fos =new FileOutputStream(file);
//3.创建缓冲流对象加强fos功能
BufferedOutputStream bos=new BufferedOutputStream(fos);
//4.向流中写入数据
bos.write(要写出的字节或者字节数组);
//5.刷新和关闭流
bos.flush();
bos.close();
//6.处理异常
由以上看出流的操作基本相同,此流与文件流操作是几乎一样的只是将文件流作为参数传入缓冲流的构造方法中堆文件流读写文件的功能进行加强
注1:在字符读入缓冲流BufferedReader 中还提供了读一行的方法 readLine() 可以读取一行文本
在字符写出缓冲流BufferedWriter 中还提供了写人一个行行分隔符的方法writeLine(),用于写出时换行
注2:此处用到的是GoF设计模式中的装潢(装饰)模式
注3:创建缓冲流的对象的装逼模式:
BufferedInputStream bis =new BufferedInputStream(
new FileInputStream(new File("文件路径")));
注4:缓冲流参数只要是一中超类的子类就行
四、对象流
ObjectInputStream ,ObjectOutputStream
不同于以上两种类型的流这里只能用字节对对象进行操作原因可以看上篇的编码表比照原理
ObjectOutputStream对象的序列化:
将java程序中的对象写到本地磁盘里用ObjectOutputStream
eg:将Person类的对象序列化到磁盘
1.创建Person类
注1:此类要实现Serializable接口,此接口为标志性接口
注2:此类要有无参的构造函数
注3:一旦序列化此类不能再修改
class Person implements Serializable{
public Person(){}
}
2.创建对象流对象
注:要增强功能可以将传入文件缓冲流
ObjectOutputStream oos =new ObjectOutputStream(
new FileOutputStream(new File("文件路径")));
3.写入对象 ,一般会将对象用集合存储起来然后直接将集合写入文件
List<Person> list =new ArrayList<>();
list.add(new Person());
...(可以添加多个)
oos.writeObject(list);
4.关闭流,处理异常
oos.flush();
oos.close();
ObjectInputStream对象的反序列化:
从本地磁盘里用ObjectInputStream将对象文件读入java程序
注1:用集合接收的时候要强转
1.创建对象流对象
ObjectInputStream ois =new ObjectInputStream(
new FileInputStream(new File("文件路径")));
2.读入对象
List<Person> list =new ArrayList<>();
List =(List<Person>)ois.readObject();
3.关闭流,处理异常
ois.close();
五、转换流:
这类流是用于将字符转换为字节输入输出,用于操作字符文件,属于字符流的子类,所以后缀为reader,writer;前缀inputstream,outputstream;注 :要传入字节流作为参赛
InputStreamReader: 字符转换输出流
OutputStreamWriter:字符转换输入流
需求:读取键盘输入的一行文本,再将输入的写到本地磁盘上
//1.获取键盘输入的字节流对象in
InputStream in =Stream.in;
/*2.用转换流将字节流对象转换为字符流对象,方便调用字符缓冲流的readeLine()方法*/
InputStreamReader isr =new InputStreamReader(in);
/*5.创建字符转换输出流对象osw,方便把输入的字符流转换为字节输出到本地文件。*/
OutputStreamWriter osw =new OutputStreamWriter(new
FileOutputStream(new File("文件名")));
/*3.现在isr是字符流,可以作为参数传入字符缓冲流中*/
BufferedReader br =new BufferedReader(isr);
/*4.可以调用字符缓冲流br的readLine()方法度一行输入文本*/
String line =null;
while((line =br.readLine()){
osw.write(line);//osw是字符流对象,可以直接操作字符串
}
注:InputStreamReader isr =new InputStreamReader(new "各种类型的字节输入流都行即是:后缀为InputStream就行");
OutputStreamWriter osw =new OutputStreamWriter(new
"后缀为OutputStream就行");
六、区别记忆
1.对象流是可以读写几乎所有类型的只要是对象就行,而字节字符流,只能读写单个字节字符或者字节字符数组,以上没有读写字节字符数组的;注意对象流只有字节流!
2.字符和字节循环读入的结束条件int i=0; (i =fis.read())!=-1
用字符数组复制文件(fr 读入流 ,fw写出流),字节流也是相同的用法
int i = 0;
char[] c = new char[1024];
while((i = fr.reade()) !=-1)){
fw.write(c,0,i);
}
3.对象流里面套缓冲流的情景:
new ObjectInputStream(new BufferedInputStream(new FileInputStream(new File(“文件路径”))));
4.记忆流及其功能的方法:
前缀表示功能,后缀表示流的类型;
比如说FileInputStream 前缀:File,表示操作的磁盘,后缀:intputstream,表示是字节输入流。
同理 FileReader:表示操作文件的字符流
ObjectInputStream :操作对象的字节输入流
5.拓展:获取键盘输入的字符的缓冲流的写法:
new BufferedReader(new InputStreamReader(System.in)));
将字节以字符形式输出到控制台的字符缓冲流的写法:
new BufferedWriter( new OutputStreamWriter(System.out))