Java学习笔记 文件File与IO流

IO流

  • 在说IO流之前,先说一下文件,因为它们大部分时候都在操作文件,也就是在操作数据
  • 附带API传送门JDK documentation
0 ,文件File
  • 可以把文件File的对象理解成一个句柄,用这个抽象的句柄来操作实际文件
  • 文件对象句柄的创建
/*File类常用的有两个构造函数,一个传String:pathname, 可以是相对路径,
也可以是绝对路径;另一个传String:parent与String:child。
*/
//比如想在C盘下创建一个a.txt的文件句柄
File file = new File("c:\\a.txt");
//比如在C:\\heihei目录下创建b.txt的文件句柄
File file2 = new File("c:\\heihei", b.txt)
这样就创建了一个句柄,它能操作C盘下a.txt这个文件(文件事先不存在也是可以创建的)
  • 一些常用方法
File类中常用方法说明
boolean createNewFile()文件路径正确且事先不存在则返回true,否则false
boolean delete()文件则删除成功返回true,是目录则需要保证是空目录
boolean exists()判断文件 / 目录是否存在,存在返回true,否则false
String getAbsolutePath()获得文件 / 目录的绝对路径
String getName()得到文件 / 目录名
String getParent()获得文件 / 目录所在目录路径
boolean isDirectory()顾名思义
boolean isFile()顾名思义, too
long length()返回文件 / 目录下字节数(即多少B)
String[] list()返回当前目录句柄下所有文件/目录路径的数组,句柄是文件会报错
File[] listFiles()返回当前目录句柄下所有文件/目录的句柄的数组,句柄是文件会报错
File[] listFiles(FileFilter filter)同上,但是事先会按照文件过滤器来过滤一下
boolean renameTo(File dest)将本句柄移动到destination文件句柄所指的文件路径下,成功会本句柄将会被删除
0.1 ,文件过滤器FIleFilter
  • 文件过滤器是一个接口,实现它的子类需要重写accpt方法,按照此方法中的规则过滤。看一个Demo。
package day16;

import java.io.File;
import java.io.FileFilter;

public class Demo {
    public static void main(String[] args) {
        File file = new File("C:\\");
        listFiles(file);
    }
    public static void listFiles(File file){
        File[] files = file.listFiles(new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                if(pathname.getName().endsWith(".avi") || pathname.isDirectory()){
                    return true;
                }
                return false;
            }
        });
        
        if(files != null && files.length > 0){
            for(File f: files){
                if(f.isDirectory())
                    listFiles(f);
                else
                    System.out.println("发现一个avi: " + f.getAbsolutePath());
            }
        }
    }
}
  • 使用内部匿名类的方法创建FileFilter的实例,句柄里的每个元素都要过一遍这个过滤器,符合条件的将会存在files[]数组里。
2 ,IO流概述
  • 可以将IO流理解为数据的流动,比如在一个java文件中,读入java文件的数据就是Input,而从java文件产生,从java文件写出至他处的,就是Output。
  • Java中的IO操作主要指java.io包下的一些常用类的使用,通过对这些常用类对数据进行读取(Input)和写出(Output)。
  • IO流的分类
    • 按流动的方向来分,可以分为输入流输出流
    • 按流动的数据类型来分,可以分为字节流字符流
      • 字节流:
        • 输入流:InputStream
        • 输出流:OutputStream
      • 字符流:
        • 输入流:Reader
        • 输出流:Writer
3 ,OutputStream
  • OutputStream是一个抽象类,用来写字节流,所有带OutputStream的类的爸爸,这个类有5个重要的方法,4个具体方法,1个抽象的。
OutputStream重要方法说明
void close()用完关闭输出流
void flush()将缓存中的数据输出,形象点理解为冲马桶
void write(byte b[], int off, int len)经典的写方法,控制开始位置和长度
void write(byte b[])将整个byte字符数组写出
abstract void write(int b)写一个字符,取int中后8位bit
3.1, FileOutputStream
  • FileOutputStream是OutputStream里最常见的直接子类。
  1. 构造方法
/**
* 开启追加模式并往C:\\c.txt中写文件,默认关闭追加模式
*/
FileOutputStream fos = new FileOutputStream("C:\\c.txt", true);
FileOutputStream fos1 = new FileOutputStream("C:\\c.txt");
  1. 3个写方法的案例
package day16;

import java.io.*;

public class Demo2 {
    public static void main(String[] args) throws IOException {
        FileOutputStream fos = new FileOutputStream("C:\\c.txt", true);
        byte bytes[] = {66, 67, 68, 69};
        fos.write(65);
        fos.write("abcde".getBytes());
        fos.write(bytes,1, 2);
        //在调用close()方法时,会自动先调用flush()方法,将缓存清空
        fos.close();
    }
}
  • c.txt文件中显示AabcdeCD
  • 用完记得关闭流
  • 若再次运行,会继续追加,而非覆盖
4,InputStream
  • InputStream也是一个抽象类,用来读字节流。是所有带InputStream的爸爸,关注其4个方法。
InputStream重要方法说明
abstract int read()一次读一个字节,最开始指向第一个,读完指向下一个,读完了返回-1
int read(byte b[])一次读一组字节,读完了返回-1,否则返回本次读取的字节长度
int read(byte b[], int off, int len)一次读一组字节中[off, off+len]的字节,读完返回-1
4.1, FileInputStream
  • FileInputStream是InputStream最常用的子类,其他的InputStream用法可借鉴FileInputStream的玩法。
  1. 构造方法
FileInputStream fis = new FileInputStream("C:\\c.txt");
  1. 常用方法案例
package day16;

import java.io.FileInputStream;
import java.io.IOException;

public class Demo3 {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("C:\\c.txt");
        //逐个字节的读取
        while(true){
            int r = fis.read();
            if(r == -1) break;
            System.out.println((char)r);
        }
        fis = new FileInputStream("C:\\c.txt");
        //一次读3个
        while(true){
            byte bytes[] = new byte[3];
            int len = fis.read(bytes);
            if(len == -1) break;
            System.out.println(new String(bytes));
        }
        fis = new FileInputStream("C:\\c.txt");
        //一次读2个,读取的结果依次放在bytes数组。比如这里的off=1;len=2,则意味着bytes[]数组中,1和2下标将被填充,0下标空着。
        while(true){
            byte bytes[] = new byte[3];
            int len = fis.read(bytes, 1, 2);
            if(len == -1) break;
            System.out.println(new String(bytes));
        }
        fis.close();
    }
}
5, Writer
  • Writer是用于写入字符流的抽象类。 子类必须实现的唯一方法是write(char [],int,int),flush()和close()。 但是,大多数子类将覆盖此处定义的一些方法,以提供更高的效率,附加功能或两者兼而有之。
  • 与写字节流的OutputStream的方法相似。可以自行对比API看
用法说明
Writer append(char c)追加一个字符
Writer append(CharSequence csq, int start, int end)按要求追加字符串
Writer append(CharSequence csq)追加字符串
5.1 ,FileWriter
  • 查看源码可以得知,FireWriter其实只实现了自己的构造方法,它直接继承OutputStreamWriter,前者重写了Writer中的抽象方法,其实归根到底只要玩append()方法就行了,而append()方法其实是在调用write()方法。

  • 看一段代码理解一下

package day16;

import java.io.FileWriter;
import java.io.IOException;

public class Demo4 {
    public static void main(String[] args) throws IOException {
        //熟悉的构造方法,写字节或字符都可以决定是否开启追加模式
        FileWriter fw = new FileWriter("c:\\b.txt", true);
        //注意到append()方法返回的是自己的引用,所以可以鬼畜重复调用
        fw.append('0').append('u');
        //也可以追加字符串
        fw.append("我认为,你很捞");
        fw.append("你在骂我");
        fw.close();
    }
}
6,Reader
  • Reader类是用于读取字符流的抽象类。 子类必须实现的唯一方法是read(char [],int,int)和close()。 但是,大多数子类将覆盖此处定义的一些方法,以提供更高的效率,附加功能或两者兼而有之。
  • 用法和InputStream中的read()方法相似。可以自行查看API。
方法说明
int read()读取一个字符,返回读取字符的长度,读完返回-1
int read(char cbuf[])读取字符串,返回的结果同上
abstract int read(char cbuf[], int off, int len)读取从off开始,长度len的字符串
6.1 ,FileReader
  • FireReader类也只不过是实现了自己的构造方法,FireReader直接继承InputStreamReader,这个具体类直接继承Reader,并实现了抽象方法。
  • 看一段代码
package day16;
import java.io.FileReader;
import java.io.IOException;

public class Demo5 {
    public static void main(String[] args) throws IOException {
        //与读字节流InputStream一样的构造方法
        FileReader fr = new FileReader("c:\\b.txt");
        char chars[] = new char[100];
        // 将读取的实际字符长度存储至变量len中
        int len = fr.read(chars);
        // 创建一个字符串接收读取到的数据
        String text = new String(chars, 0, len);
        System.out.println(text);
        System.out.println(text.length());
        fr.close();
    }
}
7,字节流转换为字符流
  • 在实际应用环境中,大部分都在传字节流,但是有时候操作字节流不如操作字符流那么方便,java提供了这样的转换方式。
7.1,InputStreamReader与OutputStreamWriter
package day16.com.java;

import java.io.*;

public class Demo6 {
    public static void main(String[] args) throws IOException {
        //字节流最大输出类OutputStream 和 字符流最大输出类Writer 组合,就成了转换类
        //参数1. OutputStream(这里是FireOutputStream,用到了多态的概念)
        //参数2. 字符编码, 如gbk,utf-8, IDEA中默认utf-8
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("c:\\c.txt"));
        //然后就可以用osw这个引用,自由快乐的操作字符流了
        osw.append("床前明月光").append(",").append("清明上河图").append(".");
        osw.close();

        //字节流中最大输入类InputStream 和 字符流中最大输入类Reader 组合,就成了转换类
        //参数1. InputStream(这里是FireOutputStream,也用到了多态的概念)
        //参数2. 字符编码,默认utf-8
        InputStreamReader isr = new InputStreamReader(new FileInputStream("C:\\c.txt"));
        //然后就可以用isr这个引用,自由快乐的操作字符流了
        while(true){
            char chars[] = new char[2];
            int len = isr.read(chars);
            if(len == -1) break;
            System.out.println(new String(chars));
        }
        isr.close();

    }
}
8, 总结
  • 总结一下,其实IO流用法都大同小异,字节流用的更多,因为毕竟计算机的蓬勃发展是在西方,只需要传英文,字节流已经够用了,哪儿想到后来普及到世界各地去了。字符流可以创建实例直接操作,也可以由字节流转换后操作。
  • 对于字节流,掌握读InputStream和写OutputStream这两个抽象类,掌握常用的读写方法和其子类的常用构造方法。
字节流抽象方法以及子类的构造方法说明
InputStreamvoid close()关闭流
InputStreamabstract int read()读一个
InputStreamint read(byte b[])读一组
InputStreamint read(byte b[], int off, int len)读一组中的几个
FileInputStreamFileInputStream(String name)构造方法,传pathname字符串
FileInputStreamFileInputStream(File file)构造方法,传file对象
字节流抽象方法以及子类的构造方法说明
OutputStreamvoid close()关闭流
OutputStreamvoid flush()冲马桶,清缓存
OutputStreamabstract void write(int b)写一个
OutputStreamvoid write(byte b[])写一组
OutputStreamvoid write(byte b[], int off, int len)写一组中的几个
FileOutputStreamFileOutputStream(String name)构造方法,传pathname字符串
FileOutputStreamFileOutputStream(String name, boolean append)构造方法,是否开启追加模式
FileOutputStreamFileOutputStream(File file)构造方法:传pathname字符串
FileOutputStreamFileOutputStream(File file, boolean append)构造方法,是否开启追加模式
  • 对于字符流,掌握读Reader和写Writer这两个抽象类,掌握常用的读写方法和常用子类的构造方法。
字符流抽象方法以及子类的构造方法说明
Readerabstract void close()关闭流
Readerint read()读一个
Readerint read(char cbuf[])读一组
Readerabstract int read(char cbuf[], int off, int len)读一组中的几个
FileReaderFileReader(String fileName)构造方法,传pathname
FileReaderFileReader(File file)构造方法,传File对象
字符流抽象方法以及子类的构造方法说明
Writerabstract void close()关闭流
Writerabstract void flush()冲马桶,清缓存
Writerabstract void write(char cbuf[], int off, int len)写一串字符
Writerappend(char c)写一个字符
Writerappend(CharSequence csq)写一组字符
Writerappend(CharSequence csq, int start, int end)写一组字符里的几个
FileWriterFileWriter(String fileName, Charset charset, boolean append)构造方法,传pathname,字符编码,是否开启追加模式
FileWriterFileWriter(File file, Charset charset, boolean append)构造方法,传File对象 ,其他同上,参数1必传,后面两个可以任意组合
  • 对于转换流(字节—>字符),掌握InputStreamReader 和 OutputStreamWriter这两个具体类,除了他们的构造方法,有点不一样,创建完之后就和操作字符流一样了。
构造方法说明
OutputStreamWriterOutputStreamWriter(OutputStream out)参数1:字节流
OutputStreamWriterOutputStreamWriter(OutputStream out, String charsetName)参数1:字节流;参数2:字符编码
构造方法说明
InputStreamReaderInputStreamReader(InputStream in)参数1:字节流
InputStreamReaderInputStreamReader(InputStream in, String charsetName)参数1:字节流;参数2:字符编码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值