java I/O编程 学习笔记

java I/O 学习笔记

一、文件对象

File类,就是文件对象

  1. 基础操作,文件删除,是否存在等

    import java.io.File;
    
    public class javaDemo{
        public static void main(String[] args) throws Exception {
            File file = new File("file.txt");
            if (file.exists()){ // 文件是否存在
                file.delete(); // 删除文件
            } else{
                file.createNewFile(); // 创建文件
            }
        }
    }
    
  2. 父目录和创建目录

    import java.io.File;
    
    public class javaDemo{
        public static void main(String[] args) throws Exception {
            File file = new File("d:"+ File.separator+"file.txt"); //文件绝对路径,/可以用separator表示
            if (!file.getParentFile().exists()){ // 获取file.txt的父目录
                file.getParentFile().mkdirs(); // 创建父目录
            }
        }
    }
    
  3. 获取文件信息

    import java.io.File;
    
    public class javaDemo{
    
        public static void main(String[] args) throws Exception {
            File file = new File("d:"+ File.separator+"file.txt");
            System.out.println(file.canRead()); // 文件是否可读
            System.out.println(file.canWrite());
            System.out.println(file.canExecute());
            System.out.println(file.isDirectory()); // 文件是目录吗
            System.out.println(file.isFile());
            System.out.println(file.length()); // 文件的大小,输出为字节,需要转化
        }
    }
    

    案例1:列出目录下的所有文件

    import java.io.File;
    
    public class javaDemo{
        public static void listDir(File file){
            if (file.isDirectory()){
                File result[] = file.listFiles(); // 列出该目录下所有的文件
                if (result != null) {
                    result = file.listFiles();
                    for (int i = 0; i < result.length; i++) {
                        listDir(result[i]); // 递归调用,读取所有的文件
                    }
                }
            }
            System.out.println(file);
        }
        public static void main(String[] args) throws Exception {
            File file = new File("C:"+ File.separator+"Intel");
            listDir(file);
        }
    }
    

    案例2:文件批量更名

    import java.io.File;
    
    public class javaDemo{
        public static void renameFile(File file){
            if (file.isDirectory()){
                File result[] = file.listFiles();
                if (result != null) {
                    result = file.listFiles();
                    for (int i = 0; i < result.length; i++) {
                        renameFile(result[i]);
                    }
                }
            } else{
                if (file.isFile()){
                    String newName = null;
                    String lastName = ".java";
                    String newLastName = ".txt";
                    if (file.getName().endsWith(lastName)){
                     newName=file.getName().substring(0,file.getName().lastIndexOf("."))+newLastName;
                        File newfile = new File(file.getParentFile(), newName);
                        file.renameTo(newfile);
                    }
                }
            }
            System.out.println(file);
        }
        public static void main(String[] args) throws Exception {
            // 给定目录,将后缀为.java的文件转为后缀为.txt的文件
            File file = new File("C:"+ File.separator+"Intel"); 
            renameFile(file);
        }
    }
    

二、文件读写

1. 字节流

1.1 OutputStream 和 InputStream

OutputStream 和 InputStream 定义了字节的输入和输入流,java的输入和输出都是这两个类的衍生,由于这两个类是abstract类,所以需要其子类的实例化对象,实现对字节的操作

1.2 FileOutputStream 和FileInputStream

这两个继承OutputStream and InputStream 从而实现对字节的操作

import java.io.*;

public class javaDemo{
    public static void main(String[] args) throws Exception {
        File file = new File("file.txt");
        
        OutputStream out = new FileOutputStream(file); // 实例化OutputStream对象
        String str = "content";
        String newStr = "new content";
        out.write(str.getBytes()); // 字符串需要转换为字节,才能写入
        out.write(newStr.getBytes()); // 文件内容追加
        out.close();
        
        InputStream in = new FileInputStream(file);
        byte[] data = new byte[1024]; // 生成一个位于内存中的字节数组缓冲区,存储读取的内容
     // byte[] data = in.readAllBytes(); // 直接读取所有的数据,存入缓冲区,字节不能过大
        int len = in.read(data); // 将in的内容读取到data数组中,并返回这个数组的大小
        System.out.println(new String(data, 0, len)) // 将缓冲区中的字节转化为字符串输出到屏幕
        in.close();
    }
}

2. 字符流

2.1 Writer 和 Reader

这两个类用来实现对字符流进行操作,但是为抽象类,因此需要子类才能实例化对象

2.2 FileWriter 和 FileReader

FileWriter and FileReader分别是OutputStreamWriter 和 InputStreamReader的子类,这就表示,字符流其实是字节流转换之后的东西

import java.io.*;

public class javaDemo{
    public static void main(String[] args) throws Exception {
        File file = new File("file.txt");
        Writer out = new FileWriter(file);
        out.write("content");
        out.append("new content");
        out.close();
        
        Reader in = new FileReader(file);
        char[] data = new char[1024]; // 创建存储字符的数组
        in.skip(9); // 跳过九个字符再进行读取
        int len = in.read(data);
        System.out.println(new String(data, 0, len));
        in.close();
    }
}

3. 字符流和字节流的区别

字节是程序的底层体现,字符则是字节的整合

字节流可以直接进行操作,但是字符流需要先读取到缓冲区,再进行转换成字符输出。因此字符流如果不适用out.close()方法关闭,必须使用out.flush()方法刷新缓冲区,才能将字符内容输出。

3.1 字符流和字节流的转换

OutputStreamWriter 和 InputStreamReader 可以实现字符流和字节流的转换,这两个类分别是Writer和Reader的子类

import java.io.*;

public class javaDemo{
    public static void main(String[] args) throws Exception {
        File file = new File("file.txt");
        OutputStream output = new FileOutputStream(file); // 写入字节流
        Writer out = new OutputStreamWriter(output); // 字节流转换为字符流
        out.write("content"); // 实现字符流的写入
        out.append("new content");
        out.flush();

        InputStream input = new FileInputStream(file); // 文件读取为节流
        Reader in = new InputStreamReader(input); // 转换
        char[] data = new char[1024];
        int len = in.read(data);
        System.out.println(new String(data, 0, len));
        in.close();
    }
}

三、字符编码

1. 获取系统默认编码

编码就是字符的语言,不同的编码方式就是英语和中文的区别,写入和读取的编码方式不同,就会出现乱码

import java.io.*;

public class javaDemo{
    public static void main(String[] args) throws Exception {
        System.out.println(System.getProperty("file.encoding"));
        OutputStream out = new FileOutputStream("file.txt");
        out.write("content".getBytes("ISO8859-1")); // 字符转为ISO编码,并写入到文件中
        out.close();
    }
}
输出:UTF-8
文件内容为乱码显示

四、内存操作流

内存操作流直接在内存中进行操作,而不是磁盘数据操作

1. 字节内存操作流

1. ByteArrayOutputStream 和ByteArrayInputStream

2. 字符内存操作流

1. CharArrayOutputStream 和CharArrayInputStream

现在被Scanner类取代

五、管道流(未学习

进行两个线程间的通信

六、RandomAccessFile

大文件的读取和小文件的读取逻辑不同,这个类主要用来实现较大文件的读取

通过对文件内部读取位置的自由定义,以实现部分数据的读取操作,所以写入时就必须保证写入数据格式与长度的统一

import java.io.*;

public class javaDemo{
    public static void main(String[] args) throws Exception {
        File file = new File("file.txt");
        RandomAccessFile raf = new RandomAccessFile(file, "rw");
        String name[] = new String[] {"zhangsan","lisi    ", "wangwu  "}; // 保证名字的8个字节必须相同
        int age[] = new int[]{30,20,14};
        for (int x= 0;x<name.length;x++){
            raf.write(name[x].getBytes());
            raf.writeInt(age[x]); // 写入整数
        }
        raf.close();
    }
}
import java.io.*;

public class javaDemo{
    public static void main(String[] args) throws Exception {
        File file = new File("file.txt");
        RandomAccessFile raf = new RandomAccessFile(file, "rw");
        {
            raf.skipBytes(24); // 跳过24个字节
            byte[] data = new byte[8];
            int len = raf.read(data);
            // trim方法去除空格
            System.out.println("姓名: "+new String(data, 0, len).trim()+ "、年龄: "+ raf.readInt());
        }
        {
            raf.seek(12);// 回跳12字节
            byte[] data = new byte[8];
            int len = raf.read(data);
            System.out.println("姓名: "+new String(data, 0, len).trim()+ "、年龄: "+ raf.readInt());
        }
        {
            raf.seek(0);
            byte[] data = new byte[8];
            int len = raf.read(data);
            System.out.println("姓名: "+new String(data, 0, len).trim()+ "、年龄: "+ raf.readInt());
        }
        raf.close();
    }
}

七、打印流

打印流是对OutputStream和Writer的装饰设计类,用来简化输入输出操作

1.字节打印流(PrintStream)和 字符打印流(PrintWriter)

import java.io.*;

public class javaDemo{
    public static void main(String[] args) throws Exception{
        File file = new File("file.txt");
        PrintWriter pu = new PrintWriter(new FileOutputStream(file));
        pu.println("姓名: 张三");
        pu.print("年龄: 13");
        pu.close();
    }
}

2. 格式化输出

import java.io.*;

public class javaDemo{
    public static void main(String[] args) throws Exception{
        File file = new File("file.txt");
        PrintWriter pu = new PrintWriter(new FileOutputStream(file));
        String name = "张三";
        int age = 18;
        double salary = 16243.243;
        pu.printf("姓名:%s、年龄:%d、收入:%9.2f", name, age, salary); // 格式化输出
        pu.close();
    }
}

%s:字符串、%d整数、%m.nf浮点数、%c字符

八、System类对I/O的支持

import java.io.*;

public class javaDemo{
    public static void main(String[] args) throws Exception{
        InputStream in = System.in;
        byte[] data = new byte[1024];
        int len = in.read(data);
        System.out.println(new String(data, 0, len));
        in.close();
    }
}

System.in 实现键盘数据的输入,但缺陷如下

  1. 数据的接受需要一个字节数组完成,如果超出数组长度,会出现数据丢失
  2. System.in为输入字节流,所以对中文的支持不够好,其相当于一个InputStream的对象

九、BufferedReader缓冲输入流

该类与System.in结合实现合理的键盘输入数据操作

该类提供了一种字符流的缓冲区数据读取,利用此类可以将读取到的数据保存在缓冲区内,而后利用内部提供的方法将读取的内容一次性读取

这个类只能接受Reader in的对象,所以要将System.in通过InputStreamReader转化为Reader对象

import java.io.*;

public class javaDemo{
    public static void main(String[] args) throws Exception{
        // 将字节流System.in转换为字符流对象
        BufferedReader buffer = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("请输入您的年龄:");
        String msg = buffer.readLine(); // 一次性读取缓冲区全部的内容
        if (msg.matches("\\d{1,3}")){
            int age = Integer.parseInt(msg);
            System.out.println("年龄为:"+age);
        } else{
            System.out.println("输入的内容不是数次,错误!");
        }
    }
}

十、Scanner类输入流工具

案例1:判断输入是否为日期

public class javaDemo{
    public static void main(String[] args) throws Exception {
        Scanner scan = new Scanner(System.in); // 可以接收Readable、File、InputStream类对象
        if (scan.hasNext("\\d{4}-\\d{2}-\\d{2}")){ //判断读取的内容是否为指定格式
            String str = scan.next("\\d{4}-\\d{2}-\\d{2}"); //读取输入
            System.out.println("出生日期: "+ (new SimpleDateFormat("yyyy-MM-dd").parse(str))); //转换
        } else{
            System.out.println("ERROR!");
        }
        scan.close();
    }
}

案例2:读取文件—文件分割符

import java.io.*;
import java.util.Scanner;

public class javaDemo{
    public static void main(String[] args) throws Exception{
        Scanner scan = new Scanner(new File("file.txt")); // 接收FIle类对象
        scan.useDelimiter("\n"); // 将换行符作为默认文件分割符
        while (scan.hasNext()){
            System.out.println(scan.next());
        }
        scan.close();
    }
}

十一、对象序列化

把对象变为二进制数据流的一种方法,从而实现对象的传输和存储

1.Serializable接口

class Member implements Serializable{}

允许使用该接口的Member类的实例化对象进行序列化处理

2.ObjectOutputStream 与 ObjectInputStream

import java.io.*;
class Member implements Serializable{ // 生成一个可以序列化的类,这个类的实例化对象可以被序列化处理
    private String name;
    private int age;

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

    public String toString(){
        return "name: "+this.name + "\n"+ "age: "+ this.age;
    }
}

public class javaDemo{
    private static final File SAVE_FILE = new File("object.member");
    public static void saveObject(Object obj) throws Exception{
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(SAVE_FILE));
        out.writeObject(obj); // 将对象变为二进制数据写入文件中
        out.close();
    }
    public static Object loadObject() throws Exception{
        ObjectInputStream in = new ObjectInputStream(new FileInputStream(SAVE_FILE));
        Object obj = in.readObject(); //读取存储对象的文件,返回这个对象
        in.close();
        return obj;
    }
    public static void main(String[] args) throws Exception {
        saveObject(new Member("bob", 12));
        System.out.println(loadObject());
    }
}

3. transient关键字

private transient String name

加上这个关键字后,对象序列化处理时,将不会将name属性进行序列化处理,也就是不会保存到对象序列化文件中,在进行反序列化操作时,name属性就是其对应数据类型的默认值。

总结

  1. java中使用File表示文件本身,从而实现各种文件操作
  2. 输入流和输出流,主要分为字符流和字节流,字节流是数据传输的基本形式,字符流需要用到缓冲区进行处理,而字节流不用缓冲区,字符流更适合中文操作
  3. 字节流和字符流都是以抽象类的形式定义的,根据其子类的不同,输入或输出的位置也不同,如果使用文件流进行对象化,则输入输出的终端位置就是文件;如果使用内存流实例化,则终端是内存。体现了java面向对象多态性的设计特点
  4. 程序将数据写入文件是,可以使用PrintStream, PrintWriter简化输出操作
  5. System提供3个支持I/O操作的常亮
    1. out: 对应显示器的标准输出
    2. err:对应错误信息打印,一般此消息不希望用户看到
    3. in:对应着标准键盘输入
  6. 使用Scanner类可以方便的进行输入流操作,读取前先使用hasNextXxx()判断是否有指定类型的数据,再使用nextXxx()方法获取数据内容
  7. 对象序列化就是将对象转为二进制数据,但对象所在的类必须有Serializable接口,类中的属性如果有transient声明,则此属性内容不会被序列化

习题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值