Java输入和输出处理

输入和输出处理

1 File类

文件:相关记录或放在一起的数据的集合

1.1 概述

java.io.File 类是文件和目录路径名的抽象表示,主要用于文件和目录的创建、查找和删除等操作。

1.2 构造方法

  • public File(String pathname) :通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。
  • public File(String parent, String child) :从父路径名字符串和子路径名字符串创建新的 File实例。
  • public File(File parent, String child) :从父抽象路径名和子路径名字符串创建新的 File实例。
  • 构造举例,代码如下:
// 文件路径名
String pathname = "D:\\aaa.txt";
File file1 = new File(pathname); 

// 文件路径名
String pathname2 = "D:\\aaa\\bbb.txt";
File file2 = new File(pathname2); 

// 通过父路径和子路径字符串
 String parent = "d:\\aaa";
 String child = "bbb.txt";
 File file3 = new File(parent, child);

// 通过父级File对象和子路径字符串
File parentDir = new File("d:\\aaa");
String child = "bbb.txt";
File file4 = new File(parentDir, child);

小贴士:

  1. 一个File对象代表硬盘中实际存在的一个文件或者目录。
  2. 无论该路径下是否存在文件或者目录,都不影响File对象的创建。

1.3 常用方法

方法名称说明
boolean exists( )判断文件或目录是否存在
boolean isFile( )判断是否是文件
boolean isDirectory( )判断是否是目录
String getPath( )返回此对象表示的文件的相对路径名
String getAbsolutePath( )返回此对象表示的文件的绝对路径名
String getName( )返回此对象表示的文件或目录的名称
boolean delete( )删除此对象指定的文件或目录
boolean createNewFile( )创建名称的空文件,不创建文件夹
long length()返回文件的长度,单位为字节, 如果文件不存在,则返回 0L
获取功能的方法
  • public String getAbsolutePath() :返回此File的绝对路径名字符串。

  • public String getPath() :将此File转换为路径名字符串。

  • public String getName() :返回由此File表示的文件或目录的名称。

  • public long length() :返回由此File表示的文件的长度。

    方法演示,代码如下:

    public class FileGet {
        public static void main(String[] args) {
            File f = new File("d:/aaa/bbb.java");     
            System.out.println("文件绝对路径:"+f.getAbsolutePath());
            System.out.println("文件构造路径:"+f.getPath());
            System.out.println("文件名称:"+f.getName());
            System.out.println("文件长度:"+f.length()+"字节");
    
            File f2 = new File("d:/aaa");     
            System.out.println("目录绝对路径:"+f2.getAbsolutePath());
            System.out.println("目录构造路径:"+f2.getPath());
            System.out.println("目录名称:"+f2.getName());
            System.out.println("目录长度:"+f2.length());
        }
    }
    输出结果:
    文件绝对路径:d:\aaa\bbb.java
    文件构造路径:d:\aaa\bbb.java
    文件名称:bbb.java
    文件长度:636字节
    
    目录绝对路径:d:\aaa
    目录构造路径:d:\aaa
    目录名称:aaa
    目录长度:4096
    

API中说明:length(),表示文件的长度。但是File对象表示目录,则返回值未指定。

绝对路径和相对路径
  • 绝对路径:从盘符开始的路径,这是一个完整的路径。
  • 相对路径:相对于项目目录的路径,这是一个便捷的路径,开发中经常使用。
public class FilePath {
    public static void main(String[] args) {
      	// D盘下的bbb.java文件
        File f = new File("D:\\bbb.java");
        System.out.println(f.getAbsolutePath());
      	
		// 项目下的bbb.java文件
        File f2 = new File("bbb.java");
        System.out.println(f2.getAbsolutePath());
    }
}
输出结果:
D:\bbb.java
D:\idea_project_test4\bbb.java
判断功能的方法
  • public boolean exists() :此File表示的文件或目录是否实际存在。
  • public boolean isDirectory() :此File表示的是否为目录。
  • public boolean isFile() :此File表示的是否为文件。

方法演示,代码如下:

public class FileIs {
    public static void main(String[] args) {
        File f = new File("d:\\aaa\\bbb.java");
        File f2 = new File("d:\\aaa");
      	// 判断是否存在
        System.out.println("d:\\aaa\\bbb.java 是否存在:"+f.exists());
        System.out.println("d:\\aaa 是否存在:"+f2.exists());
      	// 判断是文件还是目录
        System.out.println("d:\\aaa 文件?:"+f2.isFile());
        System.out.println("d:\\aaa 目录?:"+f2.isDirectory());
    }
}
输出结果:
d:\aaa\bbb.java 是否存在:true
d:\aaa 是否存在:true
d:\aaa 文件?:false
d:\aaa 目录?:true
创建删除功能的方法
  • public boolean createNewFile() :当且仅当具有该名称的文件尚不存在时,创建一个新的空文件。
  • public boolean delete() :删除由此File表示的文件或目录。
  • public boolean mkdir() :创建由此File表示的目录。
  • public boolean mkdirs() :创建由此File表示的目录,包括任何必需但不存在的父目录。

方法演示,代码如下:

public class FileCreateDelete {
    public static void main(String[] args) throws IOException {
        // 文件的创建
        File f = new File("aaa.txt");
        System.out.println("是否存在:"+f.exists()); // false
        System.out.println("是否创建:"+f.createNewFile()); // true
        System.out.println("是否存在:"+f.exists()); // true
		
     	// 目录的创建
      	File f2= new File("newDir");	
        System.out.println("是否存在:"+f2.exists());// false
        System.out.println("是否创建:"+f2.mkdir());	// true
        System.out.println("是否存在:"+f2.exists());// true

		// 创建多级目录
      	File f3= new File("newDira\\newDirb");
        System.out.println(f3.mkdir());// false
        File f4= new File("newDira\\newDirb");
        System.out.println(f4.mkdirs());// true
      
      	// 文件的删除
       	System.out.println(f.delete());// true
      
      	// 目录的删除
        System.out.println(f2.delete());// true
        System.out.println(f4.delete());// false
    }
}

API中说明:delete方法,如果此File表示目录,则目录必须为空才能删除。

1.4 目录的遍历

  • public String[] list() :返回一个String数组,表示该File目录中的所有子文件或目录。
  • public File[] listFiles() :返回一个File数组,表示该File目录中的所有的子文件或目录。
public class FileFor {
    public static void main(String[] args) {
        File dir = new File("d:\\java_code");
      
      	//获取当前目录下的文件以及文件夹的名称。
		String[] names = dir.list();
		for(String name : names){
			System.out.println(name);
		}
        //获取当前目录下的文件以及文件夹对象,只要拿到了文件对象,那么就可以获取更多信息
        File[] files = dir.listFiles();
        for (File file : files) {
            System.out.println(file);
        }
    }
}

小贴士:

调用listFiles方法的File对象,表示的必须是实际存在的目录,否则返回null,无法进行遍历。

2 I/O流

2.1 什么是IO

IO,Input/Output 简写,是指内存和外设之间的 数据复制 的过程. 输入是指数据从外设复制到内存中, 输出则是指数据从内存复制到外设.

根据外设种类可以分为磁盘IO和网络IO, 因为外设的数据读写速率较低以及 IO 会涉及到系统调用以及中断,所以通常都会比较耗时。程序优化的思路之一 就是减少 IO 。

2.2 IO的分类

根据数据的流向分为:输入流输出流

  • 输入流 :把数据从其他设备上读取到内存中的流。
  • 输出流 :把数据从内存 中写出到其他设备上的流。

格局数据的类型分为:字节流字符流

  • 字节流 :以字节为单位,读写数据的流。
  • 字符流 :以字符为单位,读写数据的流。

在这里插入图片描述

在这里插入图片描述

2.3 I/O流体系结构图

在这里插入图片描述

3 字节流

InputStream

InputStream类常用方法

int read( )

int read(byte[] b)

int read(byte[] b,int off,int len)

void close( )

int available():可以从输入流中读取的字节数目

子类FileInputStream常用的构造方法

FileInputStream(File file)

FileInputStream(String name)

在这里插入图片描述

OutputStream

OutputStream类常用方法

void write(int c)

void write(byte[] buf)

void write(byte[] b,int off,int len)

void close()

void flush():强制把缓冲区的数据写到输出流中

子类FileOutputStream常用的构造方法

FileOutputStream (File file)

FileOutputStream(String name)

FileOutputStream(String name,boolean append)

1.前两种构造方法在向文件写数据时将覆盖文件中原有的内容

2.创建FileOutputStream实例时,如果相应的文件并不存在,则会自动创建一个空的文件

在这里插入图片描述

 public static void main(String[] args) {
        String name = "小雪";
        String type = "拉布拉多";
        String master = "小明";
        try (
            FileInputStream fis  = new FileInputStream("D:\\Project\\aCode\\Test\\AdvancedPogramming\\ch7\\src\\before.txt");
            FileOutputStream fos = new FileOutputStream("D:\\Project\\aCode\\Test\\AdvancedPogramming\\ch7\\src\\after.txt")
                ){
            int len = 0;
            StringBuilder sb = new StringBuilder();
            byte[] date = new byte[1024];
            while ((len = fis.read(date)) != -1) {
                sb.append(new String(date, 0, len));
            }
            System.out.println(sb);
            String str = sb.toString().replace("替换前","替换后").replace("{name}",name).replace("{type}",type).replace("{master}",master);
            System.out.println(str);
            fos.write(str.getBytes());


        }catch (IOException e){

        }

    }

在这里插入图片描述
在这里插入图片描述

4 字符流

Reader

Reader->InputStreamReader(字节流InputStream,编码)->FileReader(路径||File对象)

Reader->BufferedReader(Reader reader)

Reader类常用方法

int read( )

int read(char[] c)

read(char[] c,int off,int len)

void close( )

InputStreamReader常用的构造方法

InputStreamReader(InputStream in)

InputStreamReader(InputStream in,String charsetName)

FileReader类

FileReader类是InputStreamReader的子类

FileReader(File file)

FileReader(String name)

该类只能按照本地平台的字符编码来读取数据,用户不能指定其他的字符编码类型

System.out.println(System.getProperty(“file.encoding”)); 获得本地平台的字符编码类型

BufferedReader类

BufferedReader类是Reader类的子类

BufferedReader类带有缓冲区,可以提高字符流写文本文件的效率

按行读取内容的readLine()方法

BufferedReader常用的构造方法

BufferedReader(Reader in)

子类BufferedReader特有的方法

readLine()

BufferReader缓冲区
1. 缓冲区的作用

BufferedReader 通过一个内部缓冲区(通常是一个字符数组 char[])来减少对底层输入流的读取操作次数。

  • 当调用 read()readLine() 等方法时,BufferedReader 并不会直接从底层输入流读取单个字符或一行数据,而是一次性从底层流中读取较大块的数据(比如 8192 个字符),存储在内部缓冲区中。
  • 随后,当用户请求更多数据时,BufferedReader 首先从缓冲区中提供数据,只有当缓冲区中的数据耗尽时,才会再次从底层流中读取更多数据并填充缓冲区。

通过这种方式,减少了每次读取操作都要访问底层流的次数,大大提高了读取的效率,尤其是对于性能较低的输入源(如网络、磁盘)。

2. 读取过程

读取数据的过程大致如下:

  1. 当调用 read() 方法时,首先检查缓冲区中是否有可用数据。
  2. 如果有,直接返回缓冲区中的数据,不与底层流进行交互。
  3. 如果没有可用数据(缓冲区为空),则从底层流中读取一定量的数据到缓冲区中,然后再从缓冲区中返回数据。

这种方式避免了频繁调用底层流的读取操作,从而提高了性能。

3. 缓冲区的实现

BufferedReader 类内部维护了一个字符数组作为缓冲区。其主要字段包括:

  • char[] buf:字符缓冲区,用于存储从底层流读取的数据。
  • int pos:当前读取到的字符位置,即缓冲区中的读取指针。
  • int count:缓冲区中实际存储的字符数,表示当前缓冲区中有效的字符个数。

具体实现步骤为:

  1. 初次读取时,缓冲区是空的,BufferedReader 从底层输入流中读取一块数据填充缓冲区,并更新 count
  2. 后续读取时,BufferedReader 从缓冲区中的当前位置开始读取,并更新 pos 指针。
  3. 缓冲区耗尽后,如果继续读取数据,BufferedReader 会再次从底层流中读取新的数据块到缓冲区。
解决读取时中文乱码
FileReader fr = new FileReader("c:\\myDoc\\hello.txt");
BufferedReader br=new BufferedReader(fr); 
FileInputStream fis=new FileInputStream("c:\\myDoc\\hello.txt");
//使用InputStreamReader并设置编码格式
InputStreamReader fr=new InputStreamReader(fis,"UTF-8"); 
BufferedReader br=new BufferedReader(fr); 

Writer类

Writer->OutputStreamWriter(OutputStream os,编码)->FileWriter(路径||File对象,是否追加)

Writer->BufferedWriter(Writer writer)

Writer类常用方法

write(String str)

write(String str,int off,int len)

void close()

void flush()

OutputStreamWriter常用的构造方法

OutputStreamWriter(OutputStream out)

OutputStreamWriter(OutputStream out,String charsetName)

FileWriter类

FileWriter类是OutputStreamWriter的子类

ileWriter (File file)

FileWriter (String name)

该类只能按照本地平台的字符编码来写数据,用户不能指定其他的字符编码类型

BufferedWriter类

在这里插入图片描述
在这里插入图片描述

BufferWriter缓冲区
1. 缓冲区的概念

BufferedWriter 在内部维护了一个字符数组作为缓冲区。每次写操作的数据会先写入这个缓冲区中,而不是直接写到底层的输出流(如文件或网络)。只有当缓冲区满了,或者明确调用了 flush()close() 方法时,才会将缓冲区中的数据一次性写入到底层输出流。

这种机制的好处是可以减少I/O设备的实际写操作次数,因为直接写入磁盘或网络的操作较慢。如果没有缓冲,每次 write() 方法调用都会进行一次实际的写入操作,这会导致性能低下。

2. 实现原理

BufferedWriter 的内部实现主要依赖于如下几步:

  • 内部缓冲区BufferedWriter 内部有一个字符数组,作为缓冲区。这个缓冲区的大小是可以在构造函数中指定的,默认大小通常是 8192 个字符(即8KB)。这个缓冲区用于暂存将要写入的字符。
  • 写入操作: 当调用 write() 方法时,数据并不会立即被写入输出流。相反,BufferedWriter 会先将数据写入其内部缓冲区。如果缓冲区已经满了,BufferedWriter 会自动将缓冲区中的数据刷新到实际的输出流中。
  • 刷新缓冲区: 当缓冲区满时,或者调用了 flush() 方法时,BufferedWriter 会将缓冲区中的内容写入实际的输出流。
  • flush() 方法: 当显式调用 flush() 方法时,BufferedWriter 会强制将缓冲区中的所有数据写入输出流。通常在执行完一系列写操作后,调用 flush() 可以确保所有数据都写入文件,而不是仍然在缓冲区中。
  • close() 方法: 在 close() 方法中,BufferedWriter 会先调用 flush() 将缓冲区中的剩余数据写入输出流,然后再关闭底层的输出流。
import java.io.*;

public class Test3 {
    public static void main(String[] args) {
        String name = "贝贝";
        String type = "拉布拉多";
        String master = "小明";
        try (
                FileInputStream fis  = new FileInputStream("D:\\Project\\aCode\\Test\\AdvancedPogramming\\ch7\\before.txt");
                FileOutputStream fos = new FileOutputStream("D:\\Project\\aCode\\Test\\AdvancedPogramming\\ch7\\after.txt", true);
                BufferedReader reader = new BufferedReader(new InputStreamReader(fis));
                BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fos));
                ){

            StringBuilder sb = new StringBuilder();
            String str;
            while ((str = reader.readLine()) != null) {
                sb.append(str);
            }
            System.out.println(sb);
            String str1 = sb.toString().replace("替换前","替换后").replace("{name}",name).replace("{type}",type).replace("{master}",master);
            System.out.println(str1);
            writer.newLine();
            writer.write(str1);
            writer.flush();

        }catch (IOException e){

        }
    }
}

5 读写二进制文件

DataInputStream类

FileInputStream的子类

与FileInputStream类结合使用读取二进制文件

DataOutputStream类

FileOutputStream的子类

与FileOutputStream类结合使用写二进制文件

//复制图片
public static void main(String[] args) {
        try(FileInputStream fis = new FileInputStream("D:\\Project\\aCode\\Test\\AdvancedPogramming\\ch7\\src\\img.jpg");
             FileOutputStream fos = new FileOutputStream("D:\\Project\\aCode\\Test\\AdvancedPogramming\\ch7\\src\\.jpg")
        ) {
            DataInputStream dis = new DataInputStream(fis);
            DataOutputStream dos = new DataOutputStream(fos);
            while (dis.available() > 0) {
                dos.write(dis.read());
            }
        }catch (Exception e) {
            e.printStackTrace();
        }

    }

6 序列化和反序列化

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

序列化的目的

  1. 持久化存储:将对象的状态保存到文件、数据库等持久化存储中,便于以后恢复使用。序列化可以把复杂的数据结构(如对象、数组等)转换为字节流,从而方便地存储或传输。
  2. 数据传输:序列化用于在网络上传输数据。比如在分布式系统或客户端-服务器通信中,将对象序列化为字节流后,便可以通过网络发送到远程服务器或其他计算机上,再通过反序列化将其恢复为原始的对象。
  3. 跨平台或跨语言通信:不同的平台或编程语言可能有各自的对象模型,序列化可以帮助将数据转换为通用格式(如JSON、XML等),使得不同语言或平台间的通信更加方便和无缝。
  4. 缓存数据:在应用程序中,为了提高性能,通常会把一些经常使用的数据缓存起来。序列化可以将这些数据转换为字节流,以便于快速读取和使用。
  5. 对象的深拷贝:通过将对象序列化然后反序列化,可以实现对象的深度拷贝,这在需要完全复制一个对象并确保其内部结构(比如嵌套对象)不共享时非常有用。

总之,序列化的目的是方便对象在内存之外的存储和传输,使其能够在不同的环境中恢复使用,特别是在分布式系统、远程调用、数据持久化等场景中发挥重要作用。

package Test5;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @author Advancer
 * @version 1.0.0
 * @ClassName Student.java
 * @Description
 * @createTime 2024年08月22日 09:42
 */
public class Student implements Serializable {
    private String name;
    private int age;
    private String sex;

    public Student(String name, int age, String sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
       this.age = age;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public static void main(String[] args) {
        List<Student> students = new ArrayList<Student>();
        Student student = new Student("小花", 18, "女");
        Student student1 = new Student("小明", 18, "男");
        Student student2 = new Student("小红", 18, "女");
        students.add(student);
        students.add(student1);
        students.add(student2);
        File file = new File("D:\\Project\\aCode\\Test\\AdvancedPogramming\\ch7\\student.txt");

        try(
                FileInputStream fis = new FileInputStream(file);
                FileOutputStream fos = new FileOutputStream(file)
        ) {
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            ObjectInputStream ois = new ObjectInputStream(fis);
            oos.writeObject(students);
            oos.flush();
            System.out.println("序列化成功");
            

            List<Student> students1 = (List<Student>) ois.readObject();
            System.out.println("反序列化成功");
            for (Student student3 : students1) {
                System.out.println(student3.getName()+" " + student3.getAge()+" "+student3.getSex());
            }

        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值