Java学习之文件io流篇

Java学习之文件io流篇0x00前言在平时的一些开发中,普遍都会让脚本运行的时候,去存储一些脚本运行结果的数据,例如开发一个爬虫,这时候我们爬取下来的内容,就需要存储到本地,那么这时候就会用到

大家好,又见面了,我是全栈君,祝每个程序员都可以多学几门语言。

Java学习之文件io流篇

0x00 前言

在平时的一些开发中,普遍都会让脚本运行的时候,去存储一些脚本运行结果的数据,例如开发一个爬虫,这时候我们爬取下来的内容,就需要存储到本地,那么这时候就会用到一些操作文件的类。

0x01 File 类

File类主要用于文件和目录创建、查找、删除等操作的。

先来查看他的构造方法

public File(String pathname) :通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。
public File(String parent, String child) :从父路径名字符串和子路径名字符串创建新的 File实例。
public File(File parent, String child) :从父抽象路径名和子路径名字符串创建新的 File实例。

常用方法:

public String getAbsolutePath() :返回此File的绝对路径名字符串。
public String getPath() :将此File转换为路径名字符串。
public String getName() :返回由此File表示的文件或目录的名称。
public long length() :返回由此File表示的文件的长度。

代码实例:

public static void main(String[] args) {
        String Pathname = "a.txt";
        File abc = new File(Pathname);
        System.out.println(abc.getAbsolutePath());
        String Pathname1 = "a\\a.txt";
        File abc1 = new File(Pathname1);
        System.out.println(abc1.getAbsolutePath());
        System.out.println(abc1.getPath());
        System.out.println(abc1.length());
    }

判断方法:

public boolean exists() :此File表示的文件或目录是否实际存在。
public boolean isDirectory() :此File表示的是否为目录。
public boolean isFile() :此File表示的是否为文件。
    public static void main(String[] args) {
        String Pathname = "a.txt";
        File abc = new File(Pathname);
        boolean a = abc.exists();
        System.out.println(a);
        System.out.println(abc.isFile());
        System.out.println(abc.isDirectory());
    }

增删功能方法

public boolean createNewFile() :当前仅当具有该名称的文件尚不存在时,创建一个新的空文件。
public boolean delete() :删除由此File表示的文件或目录。
public boolean mkdir() :创建由此File表示的目录。
public boolean mkdirs() :创建由此File表示的目录,包括任何必需但不存在的父目录。
public static void main(String[] args) throws IOException {
        String Pathname = "a.txt";
        File abc = new File(Pathname);
        boolean file = abc.createNewFile();
        System.out.println(file+"\n"+abc.getAbsolutePath());


       File abc1 = new File("abc");
       abc1.mkdir();

       File abc2 = new File("abc\\abc");
       abc2.mkdirs();
    }

如果是对目录进行删除,删除的目录必须为空才能进行删除。

目录遍历

在file里面给我们提供了,可以直接获取file目录下面所有子文件或目录。

public String[] list() :返回一个String数组,表示该File目录中的所有子文件或目录。
public File[] listFiles() :返回一个File数组,表示该File目录中的所有的子文件或目录。

代码实例:

public static void main(String[] args) throws IOException {
        String Pathname = "../";
        File abc = new File(Pathname);
        String[] name = abc.list();
        for (String s : name) {
            System.out.println(s);
        }
    }

使用list方法获取所有文件,然后使用增强for循环进行遍历。

0x02 IO流概述

IO流概述

java里面的io流指的是对一些文件内容做一个输入输出的作用。也就是input和output,对文件进行读取和输入数据的操作。

input:把数据从其他设备上读取到内存的流

output:把数据从内存写出到其他设备的流。

字节流

在计算机里面所有的文本数据包括图片、文本、视频这些在存储的时候,都是以二进制的形式进行村粗的。字节流是以一个字节为单位,读写数据的流。

字符流

以一个字符为单位,读写数据的流

0x03 字节流输出流

OutputStream抽象类是字节输入流的超类,他定义了几个共性的方法。

public void close() :关闭此输出流并释放与此流相关联的任何系统资源。
public void flush() :刷新此输出流并强制任何缓冲的输出字节被写出。
public void write(byte[] b) :将 b.length字节从指定的字节数组写入此输出流。
public void write(byte[] b, int off, int len) :从指定的字节数组写入 len字节,从偏移量 off开始输
出到此输出流。
public abstract void write(int b) :将指定的字节输出流。

在操作完成后,必须使用close方法将资源释放。

FileOutputStream 类

FileOutputStream类是文件输出流,用于将数据些出到文件当中。

查看构造方法:

public FileOutputStream(File file) :创建文件输出流以写入由指定的 File对象表示的文件。
public FileOutputStream(String name) : 创建文件输出流以指定的名称写入文件。

如果创建一个io流的对象,必须传入文件的路径,,如果没有该文件就会创建该文件,如果有就会清空原本有的数据。

代码:

public static void main(String[] args) throws IOException {
        File file = new File("a.txt");
        FileOutputStream FileoutDate = new FileOutputStream(file);
        FileoutDate.write(97);
        FileoutDate.close();
    }

这里写进入一个97,但是打开文件会发现写进入的变成了a,这是因为我们这里是以字节进行写入的,,而97的ascii转换为字符后,就是a这个字符。

这里还可以指定写出的数据长度。

public class FileOutput {
    public static void main(String[] args) throws IOException {
        File file = new File("a.txt");
        FileOutputStream FileoutDate = new FileOutputStream(file);
        byte[] b = "abce3".getBytes();
        FileoutDate.write(b,2,2);
        FileoutDate.close();
    }
    }

这里要先获取字符的字节类型数据,使用write写入,从第二位开始索引,写入2个字节。

在程序开发中,有些数据可能没法一次执行获取所有结果,这时候我们如果以上面的方式来循环写入运行结果的话,每次循环就都会被清空一次,只获得最后一次的执行结果。
那么这时候我们就可以使用到追加,把它追加进入,而不是直接覆盖重写。

public FileOutputStream(File file, boolean append) : 创建文件输出流以写入由指定的 File对象表示的
文件。
public FileOutputStream(String name, boolean append) : 创建文件输出流以指定的名称写入文件。

代码:

 public static void main(String[] args) throws IOException {
        File file = new File("a.txt");
        FileOutputStream FileoutDate = new FileOutputStream(file,true);
        byte[] b = "abce3".getBytes();
        FileoutDate.write(b,2,2);
        FileoutDate.close();
    }

这几行代码和前面的相同,只是在FileOutputStream 构造方法里面传入一个ture,表示使用追加模式,该模式默认为false。

0x04 字节输入流

InputStream抽象类是字节输入流的超类。可以读取字节数据到内存中。

共性方法:

public void close() :关闭此输入流并释放与此流相关联的任何系统资源。
public abstract int read() : 从输入流读取数据的下一个字节。
public int read(byte[] b) : 从输入流中读取一些字节数,并将它们存储到字节数组 b中 。

FileInputStream 类

FileInputStream是文件输入流,从文件中读取字节到内存中。

构造方法:

FileInputStream(File file) : 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系
统中的 File对象 file命名。
FileInputStream(String name) : 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件
系统中的路径名 name命名。

代码:

 public static void main(String[] args) throws IOException {
        File file = new File("a.txt");
        FileInputStream fileinputdata = new FileInputStream(file);
        int read = fileinputdata.read();
        System.out.println((char) read);
        read = fileinputdata.read();
        System.out.println((char) read);
        read = fileinputdata.read();
        System.out.println(read);
        fileinputdata.close();
    }

使用read方法读取完后,地址会往后推一位,知道读取到没有,会返回-1。

以上的方法都是读取单个字节,我们可以定义一个字节类型的数值,然后让他每次读取我们指定的长度。

代码:

    public static void main(String[] args) throws IOException {
        File file = new File("a.txt");
        FileInputStream fileinputdata = new FileInputStream(file);
        int len;
        byte[] b = new byte[2];
        while ((len=fileinputdata.read(b))!=-1){
            System.out.println(new String(b,0,len));
        }
        fileinputdata.close();
    }

这里定义了b变量用来接收每次读取的数据产的长度,然后定义一个len变量,接收每次读取的数据,这里可以直接把赋值放在循环条件里面,如果赋值的变量不等于-1,就一直循环,知道读取到-1,停止循环,前面说到如果没有数据读取会输出返回一个-1,结束循环。

0x05 字符流

在字节读写的时候,一些中文字符读写可能会显示乱码。因为一个中文字符可能占用多个字节。所以在一些读写的是字符数据的话,可以使用字符流来处理该数据。

字符输入流

Reader抽象类是表示用于读取字符流的超类,可以读取字符信息到内存中。

共性方法:

public void close() :关闭此流并释放与此流相关联的任何系统资源。
public int read() : 从输入流读取一个字符。
public int read(char[] cbuf) : 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中 。

FileReader 类

构造方法:

FileReader(File file) : 创建一个新的 FileReader ,给定要读取的File对象。
FileReader(String fileName) : 创建一个新的 FileReader ,给定要读取的文件的名称。

创建一个流对象,必须传入一个文件路径。

构造方法定义代码:

 public static void main(String[] args) throws IOException {
    File file = new File("a.txt");
        FileReader filereader = new FileReader(file);
    }
或者:
public static void main(String[] args) throws IOException {
        
        FileReader filereader = new FileReader("a.txt");
    }

读取单个字符数据:

public static void main(String[] args) throws IOException {

        FileReader filereader = new FileReader("a.txt");
        int b;
        while ((b = filereader.read())!=-1){
            System.out.println((char)b);
        }
    }

读取多个字符数据:

 public static void main(String[] args) throws IOException {

        FileReader filereader = new FileReader("a.txt");
        int b;
        char[] buf = new char[2];
        while ((b = filereader.read(buf))!=-1){
            System.out.println(new String(buf));
        }
    }

字符输出流

Writer抽象类是字符输出流的超累,将知道的字符信息写出到指定地方。

共性方法:

void write(int c) 写入单个字符。
void write(char[] cbuf) 写入字符数组。
abstract void write(char[] cbuf, int off, int len) 写入字符数组的某一部分,off数组的开始索引,len
写的字符个数。
void write(String str) 写入字符串。
void write(String str, int off, int len) 写入字符串的某一部分,off字符串的开始索引,len写的字符个
数。
void flush() 刷新该流的缓冲。
void close() 关闭此流,但要先刷新它。

FileWriter 类

FileWriter类是写出字符到文件中的一个类,,构造时候使用默认的字符编码和默认的字节缓冲区。

构造方法:

FileWriter(File file) : 创建一个新的 FileWriter,给定要读取的File对象。
FileWriter(String fileName) : 创建一个新的 FileWriter,给定要读取的文件的名称。

写出数据代码:

public static void main(String[] args) throws IOException {

        FileWriter filewriter = new FileWriter("a.txt");
        filewriter.write("二狗");
        filewriter.write(97);
        filewriter.write(156);
        filewriter.flush();
        filewriter.close();
    }

这里的代码,如果不写flush方法,也不写close是没法写入数据的。
来看看这2个方法的区别:

flush :刷新缓冲区,流对象可以继续使用。
close :先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。

0x06 缓存流

字节流和字符流每次读写都会访问硬盘,当读写频率增加其访问效率不高
而使用缓存流读取时会将大量数据先读取到缓存中,以后每次读取先访问缓存,直到缓存读取完毕再到硬盘读取,缓存流写入数据也是一样,先将数据写入到缓存区,直到缓存区达到一定的量,才把这些数据一起写道硬盘中去,这样减少了IO操作。

字节缓冲流: BufferedInputStream , BufferedOutputStream
字符缓冲流: BufferedReader , BufferedWriter

字节缓存输出流

构造方法:

public BufferedInputStream(InputStream in) :创建一个 新的缓冲输入流。
public BufferedOutputStream(OutputStream out) : 创建一个新的缓冲输出流。

代码:

    public static void main(String[] args) throws IOException {

        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt"));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("A.txt"));

        int b ;
        while ((b = bis.read())!=-1){
            bos.write(b);
        }
    }

上面的代码使用了字节缓存流的方式来进行了一个文件的复制粘贴,如果是使用字节输出流的方式是很慢的。而使用字节缓存流的方式读写的速度会很快。

如果我们想让读写更快的话,可以定义一个每次读写的长度,让他每次读写固定到的长度。

    public static void main(String[] args) throws IOException {

        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt"));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("A.txt"));

        int b ;
        byte[] bytes = new byte[8*1024];
        while ((b = bis.read(bytes))!=-1){
            bos.write(bytes,0,b);
        }
    }

每次读写8*1024个字节,减少文件读写的时间。

字符缓存流

构造方法:

public BufferedReader(Reader in) :创建一个 新的缓冲输入流。
public BufferedWriter(Writer out) : 创建一个新的缓冲输出流。

代码:

public static void main(String[] args) throws IOException {
        BufferedReader bis = new BufferedReader(new FileReader("a.txt"));
            String b = null ;
            while ((b = bis.readLine())!=null){
                System.out.println(b);
            }
            bis.close();
    }

使用readline读取当行数据。

0x07 序列化与反序列化

概述

java提供了一种对象序列化的机制,用一个字节序列表示一个对象,该字节包含对象的数据、对象的类型、对象的存储属性。字节序列写出到文件后,相当于可以持久报错了一个对象信息,这过程叫做序列化。

而反过来,将存储在文件的字节序列从文件中读取出来,重构对象,重新用来创建对象,这步骤叫做反序列化。

总结:简单来讲就是将一个对象,写入文件当中,而反序列化就是将写入文件的对象,读取出来。

ObjectOutputStream 类

ObjectOutputStream 类,将Java对象的原始数据类型写出到文件,实现对象的持久存储。也就是对对象进行序列化的一个类。

构造方法:

public ObjectOutputStream(OutputStream out)

注意事项:

1.使用该类必须实现Serializable 接口,Serializable是一个标记接口,不实现此接口的类将不会时任何状态序列化或者是放序列化,会抛出NotSerializableException的异常。

2.该类的所有的属性必须时可以序列化的,如果有一个属性不需要序列化的,测该属性必须标明时瞬态的,使用transient修饰符。

代码:

创建一个类:

public class Method implements Serializable {
    public String name;
    public String address;
    public transient int age;
    public void method(){
        System.out.println(name +address);
    }

}

main方法:

public static void main(String[] args) {
        Method e = new Method();
        e.name = "zhangsan";
        e.address = "beiqinglu";
        e.age = 20;

        try {
            ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("a.txt"));
            out.writeObject(e);
            out.close();
            System.out.println("ok");

        } catch (IOException ioException) {
            ioException.printStackTrace();
        }finally {
        }
    }

查看a.txt文件可以看到显示的字符都是乱码,这是因为将对象序列化了,写进入的是一个对象,而不是一些字符。

ObjectInputStream类

ObjectInputStream反序列化流,将之前使用ObjectOutputStream序列化的原始数据恢复为对象

构造方法:

public ObjectInputStream(InputStream in) : 创建一个指定InputStream的ObjectInputStream。

反序列化方法1

如果我们需要对序列化的对象,进行反序列化,将他从文件读取出来还原成对象那么我们这里调用ObjectOutputStream的readobject方法,读取一个对象。

public final Object readObject () : 读取一个对象。

代码:

 public static void main(String[] args) {
        Method e = null;
        try {
            FileInputStream fis = new FileInputStream("a.txt");
            ObjectInputStream ois = new ObjectInputStream(fis);
             e = (Method) ois.readObject();
            ois.close();
            fis.close();
        } catch (IOException | ClassNotFoundException ioException) {
            ioException.printStackTrace();
        }
        System.out.println("name="+e.name);
        System.out.println("address ="+e.address);
        System.out.println("age="+e.age);
    }

反序列化方法2

当jvm方序列化对象的时候,能找到class属性,,但是class文件在序列化之后修改了,那么反序列化操作肯定是失败的,会抛出InvalidClassException。

抛出InvalidClassException的一次原因有3种:

1.该类的序列版本号与从流中读取的类描述符的版本号不匹配

2.该类包含未知数据类型

3.该类没有可访问的无参数构造方法

Serializable 接口给需要序列化的类,提供了一个序列版本号。 serialVersionUID 该版本号的目的在于验证序
列化的对象和对应类是否版本匹配。

public class Employee implements java.io.Serializable {
// 加入序列版本号
private static final long serialVersionUID = 1L;
public String name;
public String address;
// 添加新的属性 ,重新编译, 可以反序列化,该属性赋为默认值.
public int eid;
public void addressCheck() {
System.out.println("Address check : " + name + " ‐‐ " + address);
}
}

0x08 总结


File类:用于创建删除文件与文件夹。

FileoutputStream:字节输出流,用于将字节写出到文件中。

FileinputStream:字节输出流,用于读取文件中的字节。

FileReader类是表示用于读取字符流,可以读取字符信息到内存中。

FileWriter类是写出字符到文件中的一个类,,构造时候使用默认的字符编码和默认的字节缓冲区。

字节缓冲流: BufferedInputStream , BufferedOutputStream

字符缓冲流: BufferedReader , BufferedWriter

0x09 结尾

这篇文章的内容比较多,在后面也写了个简单的小总结,这篇也写了我2天左右。后面去深入研究一下历史爆出的一些反序列化漏洞。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/119950.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • linux局域网传输文件,局域网传输文件详解(转)[通俗易懂]

    linux局域网传输文件,局域网传输文件详解(转)[通俗易懂]局域网传输文件详解(转)相信很多朋友都有过这样的经历,在办公室需要通过局域网传输文件。如果顺利自然不必说了,但有时难免也会遇到“不测”,尤其是直接移动文件,万一失败损失惨重,虽然几率不大但毕竟存在。我们该如何做呢?大家知道,本身的复制功能是不能实现断点续传的,也就是说如果在局域网中复制文件一旦失败,原先复制的文件就要重新复制,这种情况相信大家也曾有过体会,难道在局域网中复制文件还不如在互联网上下…

  • HTML 动画(一)[通俗易懂]

    HTML 动画(一)[通俗易懂]入场动画(一)图片从左至右逐渐消失实现逻辑:a:将遮罩分割为数个div,多个div通过图片定位拼接成一张图片;b:运用requestAnimationFrame+animation实现动画;c:遮罩层网格状逐步消失设置background-position:0;2.效果图:3.代码:<!DOCTYPEhtml><htmllang=”en”&…

  • 使用树莓派实现的口罩检测

    使用树莓派实现的口罩检测基于树莓派3B+官方摄像头两个指示灯实现的口罩检测项目演示链接口罩检测项目地址使用的口罩检测项目是AIZOO团队实现的使用的是目标检测常用的SSD算法。(由于疫情在家连不上实验室的服务器我无法训练)项目GitHub链接AIZOO团队给出的代码在Windows上很容易以跑通。配置的环境相对比较容易。也不需要很复杂的更改代码。因为模型较小我想出要在树莓派上运行,就进行了一些尝试。但是要在树莓派上运行需要修改一些代码。树莓派配置参考链接有很多基础配置对树莓派进行换源.

  • python爬取股票代码_python爬取所有股票的个股资讯「建议收藏」

    python爬取股票代码_python爬取所有股票的个股资讯「建议收藏」前言由于毕设是要对股票的新闻报道进行情感分析,所以爬取所有股票的个股资是必要的前提工作了。一开始准备直接在东方财富网上爬取所有的个股资讯,但是在获得个股资讯列表的时候要模拟事件。前提工作安装python3(下载地址),在安装的时候选择添加到环境变量,如果没有选择,可以通过【右键我的电脑】->【属性】->【高级系统设置】->【环境变量】->【path】将安装的Python3的…

    2022年10月30日
  • RadControls for Windows 8

    RadControls for Windows 8RadControlsforWindows8http://www.telerik.com/help/wpf/radchartview-populating-with-data-static-data.htmlRadCartesianChartchart=newRadCartesianChart();      chart.HorizontalAxi

  • 容斥原理的证明_容斥原理三集合公式解释

    容斥原理的证明_容斥原理三集合公式解释容斥原理的证明原链接地址容斥原理(翻译)-vici-C++博客       我们要证明下面的等式:                其中B代表全部Ai的集合         我们需要证明在Ai集合中的任意元素,都由右边的算式被正好加上了一次(注意如果是不在Ai集合中的元素,是不会出现在右边的算式中的)。         假设有一任意元素在k个A

    2022年10月27日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号