Java最基础IO知识各类流

输入、输出流


前记:

  • 简单先过了一遍教材的IO知识
  • 第一次简单参照JDK1.8文档来学习
一、基本概念

等回去看Java核心技术卷二时再来补充。

两大IO家族:

在这里插入图片描述

在这里插入图片描述

二、File类
1、定义

来自JDK1.8官方文档:

  • 是用来文件和目录路径名的抽象表示。
  • 该实例File类是不可变的; 也就是说,一旦创建,由File对象表示的抽象路径名永远不会改变。
  • 主要用来获得文件或目录本身的一些信息,不涉及对文件的读取
  • 可选系统有关的前缀字符串,如磁盘驱动器符, “/“为UNIX根目录,或**”\\”(因为字符串中\代表转义)**的Microsoft Windows UNC路径
  • 注意:file重写了toString()方法。,返回创建该对象时的完整路径(包括文件名等)。
2、构造方法
一共有三种常用构造方法(其实一共有四个):   
File file = new File("C:\\Users\\aj\\Desktop\\IO\\1.txt");
File file = new File("C:\\Users\\aj\\Desktop\\IO", "1.txt");
File file = new File(file, "1.txt");//其中,file是一个File对象,是一个路径
3、操作文件
public class TestMain3{
    public static void main(String[] args) throws IOException {
        File file = new File("C:\\Users\\aj\\Desktop\\IO\\1.txt");
        //File file = new File("C:\\Users\\aj\\Desktop\\IO", "1.txt");
        //File file = new File(file, "1.txt");
        System.out.println(file.createNewFile());//创建一个新文件,如果已经存在,创建失败
        System.out.println(file.getName());//得到简要名称
        System.out.println(file.canRead());//判断是否可读
        System.out.println(file.canWrite());//判断是否可写
        System.out.println(file.exists());//判断是否存在
        System.out.println(file.length());//得到文件长度大小,如果是目录为0
        System.out.println(file.getAbsolutePath());//得到绝对路径
        System.out.println(file.getParent());//得到上一级目录名
        System.out.println(file.isFile());//判断是否是一个文件
        System.out.println(file.isDirectory());//判断是否是一个目录
        System.out.println(file.isHidden());//判断是否是隐藏文件
        System.out.println(file.lastModified());//得到文件最后修改时间
        System.out.println(file.delete());//删除文件,如果是目录,则要为空才能删除
    }
}
/**输出如下:
false
1.txt
true
true
true
0
C:\Users\aj\Desktop\IO\1.txt
C:\Users\aj\Desktop\IO
true
false
false
1607950742446
true

Process finished with exit code 0
**/
4、操作目录

创建目录

public class TestMain3{
    public static void main(String[] args) throws IOException {
        File file = new File("C:\\Users\\aj\\Desktop\\IO", "1");
        if (!file.exists()) {
            //boolean mkdirs = file.mkdirs();//创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录。
            // 请注意,如果此操作失败,它可能已成功创建一些必需的父目录。
            System.out.println("创建目录成功吗?" + file.mkdir());//仅创建当前目录
        }
    }
}
/**
创建目录成功吗?true

Process finished with exit code 0
**/

列出所有文件

public class TestMain3{
    public static void main(String[] args) throws IOException {
        File file = new File("C:\\Users\\aj\\Desktop\\IO");
        String[] list = file.list();
        for (String s : list) {
            System.out.println(s);//可以看到,返回的是文件或目录的名字,不含路径,如果配合路径操作,可以利用file对象
        }
        System.out.println("-------");
        File[] files = file.listFiles();
        for (File file1 : files) {
            System.out.println(file1);//可以看到得到的是绝对路径的File对象
        }
    }
}
/**
Notepad++.lnk
文件夹1
腾讯QQ.lnk
阿里巴巴Java开发手册(详尽版).pdf
-------
C:\Users\aj\Desktop\IO\Notepad++.lnk
C:\Users\aj\Desktop\IO\文件夹1
C:\Users\aj\Desktop\IO\腾讯QQ.lnk
C:\Users\aj\Desktop\IO\阿里巴巴Java开发手册(详尽版).pdf

Process finished with exit code 0
**/

列出已过滤的文件

public class TestMain3{
    public static void main(String[] args) throws IOException {
        File file = new File("C:\\Users\\aj\\Desktop\\IO");

        System.out.println("该目录下所有文件及目录如下");
        String[] allFiles = file.list();
        for (String file2 : allFiles) {
            System.out.println(file2);
        }

        System.out.println("--------------");
        System.out.println("过滤了.lnk后");
        String[] list = file.list((dir, name) -> {
            //dir是一个File类型的参数,只是这里没用到而已,并不代表它没有用
            return name.endsWith(".lnk");
        });
        for (String s : list) {
            System.out.println(s);
        }

        System.out.println("------------");
        System.out.println("过滤了.html后");
        fileNameFilterImp fileNameFilterImp = new fileNameFilterImp();
        fileNameFilterImp.setSuffix("html");
        File[] files = file.listFiles(fileNameFilterImp);
        for (File file1 : files) {
            System.out.println(file1);
        }
    }
}

class fileNameFilterImp implements FilenameFilter {
    //如果实现了FileFilter,则只对File对象(会把所有文件都转为File对象)进行过滤判断,因此没有参数name
    private String suffix = null;//设置要过滤的后缀

    @Override
    public boolean accept(File dir, String name) {//参数dir即为调用这个过滤器时的目录File,name为目录下的文件名(包括目录)
        return name.endsWith("." + suffix);//如果文件名以name
    }

    public String getSuffix() {
        return suffix;
    }

    public void setSuffix(String suffix) {
        this.suffix = suffix;
    }
}
/**
该目录下所有文件及目录如下
CodeBlocks.lnk
Notepad++.lnk
showLikeDetails.html
songDetails.html
userLogin.html
userRegister.html
文件夹1(故意加上.lnk后缀).lnk
文件夹2
腾讯QQ.lnk
阿里巴巴Java开发手册(详尽版).pdf
--------------
过滤了.lnk后
CodeBlocks.lnk
Notepad++.lnk
文件夹1(故意加上.lnk后缀).lnk
腾讯QQ.lnk
------------
过滤了.html后
C:\Users\aj\Desktop\IO\showLikeDetails.html
C:\Users\aj\Desktop\IO\songDetails.html
C:\Users\aj\Desktop\IO\userLogin.html
C:\Users\aj\Desktop\IO\userRegister.html

Process finished with exit code 0
**/
三、文件字节流
1、FileInputStream
Modifier and TypeMethod and Description
intavailable() 返回从此输入流中可以读取(或跳过)的剩余字节数的估计值,而不会被下一次调用此输入流的方法阻塞。
voidclose() 关闭此文件输入流并释放与流相关联的任何系统资源。
protected voidfinalize() 确保当这个文件输入流的 close方法没有更多的引用时被调用。
FileChannelgetChannel() 返回与此文件输入流相关联的唯一的FileChannel对象。
FileDescriptorgetFD() 返回表示与此 FileInputStream正在使用的文件系统中实际文件的连接的 FileDescriptor对象。
intread() 从该输入流读取一个字节的数据。
intread(byte[] b) 从该输入流读取最多 b.length个字节的数据为字节数组。
int==read(byte[] b, int off, int len)==从该输入流读取最多 len字节的数据为字节数组。
longskip(long n) 跳过并从输入流中丢弃 n字节的数据。
public class TestMain3{
    public static void main(String[] args) throws IOException {
        File file = new File("C:\\Users\\aj\\Desktop\\IO", "testFileInputStream.txt");
        FileInputStream fileInputStream = new FileInputStream(file);//也可以用String来构造
        byte[] result = new byte[5];
        int n;
        int readCount = 0;
        while ((n = fileInputStream.read(result)) != -1) {//把成功读取的字节数赋给n
            String string = new String(result, 0, n);//把从0到n的字节数组转为String对象
            System.out.print(string);
            ++readCount;
        }
        System.out.println();
        System.out.println("文件大小=" + file.length() + "个字节");
        System.out.println("一次读取" + result.length + "个字节");
        System.out.println("共读取了" + readCount + "次");
        
        fileInputStream.close()//如果不关闭,其它程序会访问不到。程序结束后虽然会自动关闭
    }
}
/**文件内容:
hello my name is Piggg.
i am from the moon.
中文来了!怕不怕
**/
/注意:因为是按字节读的,所以中文很有可能会乱码!!
/**输出:
hello my name is Piggg.
i am from the moon.
中���来了��怕���怕
文件大小=70个字节
一次读取5个字节
共读取了14次
**/
2、FileOutputStream

注意:构造的时候,如果没有append参数,则会创建新文件,把原来的文件覆盖掉。

构造方法

Constructor and Description
FileOutputStream(File file) 创建文件输出流以写入由指定的 File对象表示的文件。
FileOutputStream(File file, boolean append) 创建文件输出流以写入由指定的 File对象表示的文件。
FileOutputStream(FileDescriptor fdObj) 创建文件输出流以写入指定的文件描述符,表示与文件系统中实际文件的现有连接。
FileOutputStream(String name) 创建文件输出流以指定的名称写入文件。
FileOutputStream(String name, boolean append) 创建文件输出流以指定的名称写入文件。

方法

Modifier and TypeMethod and Description
voidclose() 关闭此文件输出流并释放与此流相关联的任何系统资源。
protected voidfinalize() 清理与文件的连接,并确保当没有更多的引用此流时,将调用此文件输出流的 close方法。
FileChannelgetChannel() 返回与此文件输出流相关联的唯一的FileChannel对象。
FileDescriptorgetFD() 返回与此流相关联的文件描述符。
voidwrite(byte[] b)b.length个字节从指定的字节数组写入此文件输出流。
voidwrite(byte[] b, int off, int len)len字节从位于偏移量 off的指定字节数组写入此文件输出流。
voidwrite(int b) 将指定的字节写入此文件输出流。 //一个字节表示的整数,可以从0到127,即ASCILL码,如传入65,会写入A
public class TestMain3{
    public static void main(String[] args) throws IOException {
        File file = new File("C:\\Users\\aj\\Desktop\\IO", "testFileInputStream.txt");
        FileOutputStream fileOutputStream = new FileOutputStream(file);
        byte[] bytes = "i love apples and phones.".getBytes();
        fileOutputStream.write(bytes);//写入完整数组
        fileOutputStream.write(65);//写入字母 A
        fileOutputStream.write(bytes, 0 , 3);//标准英文中,1个字符占一个字节,所以写入i l
        //注意,只要不关闭输出流,那么会一直拼接在文件,而不会像创建输出流对象时会出现覆盖文件的情况
        fileOutputStream.close();
    }
}
/**
输出到文件的内容:
i love apples and phones.Ai l
**/
四、文件字符流

基本方法与文件字节流差不多,只是把对byte类型的操作更换为char类型的操作。

(感觉最后一个类就是为了名称好看,因为它没有具体方法,全部都从父类继承过来。。。就构造方法有更新)

(额可能是我现在太肤浅,没理解这样设计要干啥🐷。。。)

(哦,现在知道了,从构造方法中可以看出,FileReader/FileWriter是面向File类的,而InputStreamReader/OutPutStreamWriter是面向流的)

用到的:Reader – InputStreamReader – FileReader

​ Writer – OutPutStreamWriter – FileWriter

/**
 * 从A.txt中以字符形式读取文件,并送到B.txt中,并在最后加上一句表扬的话
 */
public class TestMain3{
    public static void main(String[] args) throws IOException {
        File fileA = new File("C:\\Users\\aj\\Desktop\\IO\\A.txt");
        File fileB = new File("C:\\Users\\aj\\Desktop\\IO\\B.txt");
        if (!fileA.exists()) {
            System.out.println(fileA.createNewFile());
        }
        if (!fileB.exists()) {
            System.out.println(fileB.createNewFile());
        }
        FileReader fileReader = new FileReader(fileA);
        FileWriter fileWriter = new FileWriter(fileB, false);
        char[] result = new char[5];
        int n;
        int count = 0;
        while ((n = fileReader.read(result)) != -1) {//如果到文件尾,则返回-1
            fileWriter.write(result, 0 , n);//一次要设置一个n,因为result数组可能填不满
            count++;
        }
        System.out.println("-------");
        System.out.println("一次读取5个字符");
        System.out.println("共读了" + count + "次");
        fileWriter.write("\n说得对,说得好,说得呱呱叫");//可以写入String类型哦
        fileReader.close();
        fileWriter.close();
    }
}
/**
A.txt:
Java是一门面向对象编程语言,
不仅吸收了C++语言的各种优点,
还摒弃了C++里难以理解的多继承、指针等概念,
因此Java语言具有功能强大和简单易用两个特征。
Java语言作为静态面向对象编程语言的代表,
极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。
**/
/********************************************************************
B.txt:
Java是一门面向对象编程语言,
不仅吸收了C++语言的各种优点,
还摒弃了C++里难以理解的多继承、指针等概念,
因此Java语言具有功能强大和简单易用两个特征。
Java语言作为静态面向对象编程语言的代表,
极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。
说得对,说得好,说得呱呱叫
**/
/********************************************************************
输出:
-------
一次读取5个字符
共读了29次

Process finished with exit code 0
**/
五、缓冲流
  • 从字符输入(出)流读取(写入)文本,缓冲字符,以提供字符,数组和行的高效读取(写入)
  • BufferedReader和BufferedWriter称为上层流,而它们指向的字符流称为底层流
  • 关闭输出流时,首先关闭缓冲流,再关闭缓冲流指向的流,即先关闭底层流再关闭上层流。写代码时,只要关闭上层流即可,底层流会自动关闭。
/**
功能与上面那个程序一样
**/
public class TestMain3{
    public static void main(String[] args) throws IOException {
        BufferedReader bufferedReader = new BufferedReader(new FileReader("C:\\Users\\aj\\Desktop\\IO\\A.txt"));
        BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("C:\\Users\\aj\\Desktop\\IO\\B.txt"));
        String s;
        while ((s = bufferedReader.readLine()) != null) {
            bufferedWriter.write(s);
            bufferedWriter.newLine();//新建一个空行
        }
        bufferedWriter.write("说得对,说得好,说得呱呱叫");
        bufferedWriter.flush();
        bufferedReader.close();
        bufferedWriter.close();
    }
}
六、随机流与数据流
  • 数据流和随机流都涉及到了非常复杂的编码知识,可以参看文章:https://blog.csdn.net/qq_47234534/article/details/111349801
  • 实现了DataInput接口和DataOutput接口即数据流,所以可以对文件同时进行输入输出
Constructor and Description
RandomAccessFile(File file, String mode) 创建一个随机访问文件流从File参数指定的文件中读取,并可选地写入文件。
RandomAccessFile(String name, String mode) 创建随机访问文件流,以从中指定名称的文件读取,并可选择写入文件。

mode:r(只读)、rw(可读写)(更多看官方文档)

注意:输出时,它不会刷新文件。

Modifier and TypeMethod and Description
voidclose() 关闭此随机访问文件流并释放与流相关联的任何系统资源。
longgetFilePointer() 返回此文件中的当前偏移量。
longlength() 返回此文件的长度。
intread() 从该文件读取一个字节的数据。
intread(byte[] b) 从该文件读取最多 b.length字节的数据到字节数组。
intread(byte[] b, int off, int len) 从该文件读取最多 len个字节的数据到字节数组。
StringreadLine() 从此文件中读取下一行文本。
voidseek(long pos) 设置文件指针偏移,从该文件的开头测量,发生下一次读取或写入。
voidsetLength(long newLength) 设置此文件的长度。
intskipBytes(int n) 尝试跳过 n字节的输入丢弃跳过的字节。
voidwrite(byte[] b) 从指定的字节数组写入 b.length个字节到该文件,从当前文件指针开始。
voidwrite(byte[] b, int off, int len) 从指定的字节数组写入 len个字节,从偏移量 off开始写入此文件。
public class TestMain3{
    public static void main(String[] args) throws IOException {
        File file = new File("C:\\Users\\aj\\Desktop\\IO\\A.txt");
        RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
        double[] data = {1.2, 2, 3, 4, 5, 6.6, 7};
        for (int i = 0; i < 7; i++) {
            randomAccessFile.writeDouble(data[i]);
        }
        for (int i = 6; i >= 0; i--) {
            randomAccessFile.seek(i * 8);
            System.out.println(randomAccessFile.readDouble());
            System.out.println();
        }
    }
}
七、数组流
  • 流的源和目的地除了可以是文件外,还可以是计算机内存
  • 字节数组流和字符数组流分别是InputStream家庭和Reader家庭的
public class TestMain3{
    public static void main(String[] args) throws IOException {
        byte[] bytes = "You are a pig".getBytes();
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();//不像文件流要指定文件
        byteArrayOutputStream.write(bytes);//向内存写
        System.out.println(new String(byteArrayOutputStream.toByteArray()));//把缓冲中的字节数组打印出来

        byte[] bytes2 = new byte[byteArrayOutputStream.toByteArray().length];//新建一个内存,因为要从内存中读东西进来
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());//构建读取的时候,要指定从哪个数组流读取
        byteArrayInputStream.read(bytes2);//读
        System.out.println(new String(bytes2));
    }
}
八、对象流
  • 写入文件后,再读出来,可以得到两个完全不同的对象,因此可以用于对象克隆
  • 如果对象内的数据域含有另一个对象,那么另一个对象也是要实现Serializable标记接口
public class TestMain4 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        TV tv = new TV();
        tv.name = "国家级电视";
        tv.price = 3.0;
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("C:\\Users\\aj\\Desktop\\IO\\A.txt"));
        objectOutputStream.writeObject(tv);
        objectOutputStream.close();
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("C:\\Users\\aj\\Desktop\\IO\\A.txt"));
        TV tv2 = (TV)objectInputStream.readObject();
        System.out.println(tv == tv2);//从这里的结果false可以看到,这两个对象是完全不同的两个对象,因此可以应用于对象的克隆
        System.out.println(tv2.name);
        System.out.println(tv2.price);
    }
}

class TV implements Serializable {//要实现Serializable接口,这是一个标记接口
    String name;
    double price;
}

//输出如下:
false
国家级电视
3.0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Meow_Sir

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值