【Java笔记】(四):IO操作

File类常用操作

File是文件和目录的路径的抽象表示,它并不是一个真正的文件,仅仅是路径名,可以存在也可以不存在

方法 说明
File(String pathname) 直接写路径进行构造
File(String parent,String child) 目录和子目录进行拼接,都是String
File(File file,String child) 前面是文件,后面是子目录的文件名
exists() 判断文件是否存在
isDirectory() 判断是否是文件夹
isFile() 判断是否是文件(非文件夹)
length() 获取文件长度
lastModified() 获取文件最后修改时间
setLastModified(0) 设置文件修改时间为1970.1.1 08:00:00
f1.renameTo(f2) 文件重命名
list() 字符串数组的形式,返回当前文件夹下的所有文件
listFiles() 文件数组的形式,返回当前文件夹下的所有文件
getParent() 以字符串形式返回文件所在文件夹
getParentFile() 以文件形式返回获取所在文件夹
mkdir() 创建文件夹,如果父文件夹skin不存在,创建就无效
mkdirs() 创建文件夹,如果父文件夹skin不存在,就会创建父文件夹
createNewFile() 创建一个空文件,如果父文件夹skin不存在,就会抛出异常
getParentFile().mkdirs() 创建一个空文件之前,通常都会创建父目录
listRoots() 列出所有的盘符c: d: e: 等等
delete() 刪除文件
deleteOnExit(); VM结束的时候,刪除文件,常用于临时文件的删除

递归遍历目录

public class Test {
    
    
    public static void main(String[] args) {
    
    
        //给定一个路径
        File srcFile = new File("E:\\IdeaProjects\\javatest");
        //调用方法
        getAllFilePath(srcFile);
    }
    public static void getAllFilePath(File srcFile) {
    
    
        File[] files = srcFile.listFiles();
        if (files != null) {
    
    
            for (File file : files) {
    
    
                if (file.isDirectory()) {
    
    
                    //递归调用
                    getAllFilePath(file);
                } else {
    
    
                    System.out.println(file.getAbsolutePath());
                }
            }
        }
    }
}

IO流的概述与分类

IO:输入(读)/输出(写)(Input/Output),从其他位置加载到程序(内存)中称为输入,反之称为输出

流:流是一种抽象概念,是对数据传输的总称,数据在设备间的传输称为流,流的本质是数据传输

按数据的流向分:

  • 输入流:读数据
  • 输出流:写数据

按数据类型分:

  • 字节流(万能):字节输入流、字节输出流
  • 字符流:字符输入流、字符输出流

我们说的IO流的分类一般是按数据类型分的

InputStream与OutputStream

InputStream是一个抽象类,是所有输入字节流类的超类

OutputStream也是一个抽象类,是所有字节输出流类的超类,输出流接收输出字符并将其发送到某个接收器

字节流写数据(字节输出流FileOutputStream)

如果文件不存在会自动创建,写数据的时候有三种方式

方法 说明
write(int b) 一次写一个字节
write(byte[] b) 直接写一个字节数组
write(byte[] b,int off,int len) 从off开始写,写的长度为len

通常情况下,close方法放在finally中,在close的时候先判断是否为null

public class Test {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //给定一个路径,调用系统功能创建文件
        FileOutputStream fos = new FileOutputStream("E:\\IdeaProjects\\javatest\\fos.txt");
        //写数据,这里直接写97的时候是a
        fos.write("97".getBytes());
        //关闭流并释放系统资源
        fos.close();
    }
}

字节流写数据如何换行以及追加

换行通过写入换行符即可,不同系统换行符不同:

  • windows:\r\n
  • Linux:\n
  • mac:\r

追加写入的实现,在创建FileOutputStream的时候在后面添加true,这样就是追加了

FileOutputStream fos = new FileOutputStream("E:\\IdeaProjects\\javatest\\fos.txt",true);

字节流读数据(字节输入流FileInputStream)

public class Test {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //给定一个路径,调用系统功能创建文件
        FileInputStream fis = new FileInputStream("E:\\IdeaProjects\\javatest\\fos.txt");
        //读数据,一次读一个字节,如果文件达到末尾则返回-1
        int read = fis.read();
        System.out.println((char)read);
        
        //一次读完所有的内容
        int data;
        while ((data=fis.read())!=-1) {
    
    
            System.out.println((char) data);
        }
        
        //一次读取字节数组(常用)
        byte[] bytes = new byte[1024];
        int len;
        while ((len=fis.read(bytes))!=-1) {
    
    
            //这里经常写为fos.write(bytes);即写入输出流
            System.out.println(new String(bytes));
        }
        
        //关闭流并释放系统资源
        fis.close();
    }
}

★【经典文件复制案例】:使用字节数组

public class Test {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //输入流读数据
        FileInputStream fis = new FileInputStream("E:\\IdeaProjects\\javatest\\fos.txt");
        //输出流写数据
        FileOutputStream fos = new FileOutputStream("E:\\IdeaProjects\\javatest\\fos-backup.txt");

        byte[] bytes = new byte[1024];
        int len;
        while ((len=fis.read(bytes))!=-1) {
    
    
            fos.write(bytes);
        }

        //关闭流并释放系统资源
        fos.close();
        fis.close();
    }
}

字节缓冲流

  • BufferedOutputStream:类实现一个缓冲输出流。通过设置这样的输出流,一个应用程序可以写字节到基本的输出流,而不必导致每个字节写入的底层系统的调用。默认大小为8192字节

  • BufferedInputStream:当 BufferedInputStream创建,内部缓冲区创建数组。根据需要从流中读取字节或跳过时,内部缓冲区根据需要从包含的输入流中重新填充,一次许多字节。默认大小为8192字节

因为使用了缓冲流,大大减少了对底层的调用次数,因此可以提高效率。

注:字节缓冲流仅仅提供缓冲区,而真正的读写数据还是要依靠基本的字节流对象,因此构造方法中传入字节输入输出流,同时调用的方法与字节流对象相同

★【经典文件复制案例】:使用字节缓冲流

public class Test {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //输入流读数据
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\IdeaProjects\\javatest\\fos.txt"));
        //输出流写数据
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E:\\IdeaProjects\\javatest\\fos-backup.txt"));

        byte[] bytes = new byte[1024];
        int len;
        while ((len=bis.read(bytes))!=-1) {
    
    
            bos.write(bytes);
        }

        //关闭流并释放系统资源
        bos.close();
        bis.close();
    }
}

为什么会有字符流

字节流操作汉字或韩文、日文的时候不方便,因为读的时候是一个字节一个字节的读,而汉字在UTR-8编码下占用3个字节,在GBK编码下占用2个字节,因此直接输出会乱码,于是Java提供了字符流

字符流 = 字节流+编码表

注:汉字在存储的时候,不论使用哪种编码存储,第一个字节都是负数

字符编码解码的方法

public class Test {
    
    
    public static void main(String[] args) throws IOException {
    
    
        String s = "中国";
        //默认是UTF-8
        //[-28, -72, -83, -27, -101, -67]
        System.out.println(Arrays.toString(s.getBytes()));
        //[-28, -72, -83, -27, -101, -67]
        System.out.println(Arrays.toString(s.getBytes("UTF-8")));
        //[-42, -48, -71, -6]
        System.out.println(Arrays.toString(s.getBytes("GBK")));

        byte[] bytes = s.getBytes();
        //中国
        System.out.println(new String(bytes));
        //中国
        System.out.println(new String(bytes,"UTF-8"));
        //涓浗
        System.out.println(new String(bytes,"GBK"));
    }
}

Reader和Writer

Reader:字符输入流的抽象类

Writer:字符输出流的抽象类

字符流写数据(字符输出流OutputStreamWriter)

方法 说明
write(int c) 一次写一个字符
write(char[] c) 直接写一个字节数组
write(char[] c,int off,int len) 写一个字符数组的一部分,写的长度为len
write(String str) 写一个字符串(常用)
writer(String str,int off,int len) 写一个字符串的一部分(常用)
public class Test {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //第二个参数可以指定字符集
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("E:\\IdeaProjects\\javatest\\a.txt"));
        //刷新流,将数据进行操作,即从缓冲区释放
        osw.flush();
        osw.write("我爱你哦哦哦哦哦");
        osw.close();
    }
}

注:close首先会先刷新流,然后再关闭资源

字符流读数据(字符输入流OutputStreamReader)

public class Test {
    
    
    public static void main(String[] args) throws IOException {
    
    
        InputStreamReader isr = new InputStreamReader(new FileInputStream("E:\\IdeaProjects\\javatest\\a.txt"));
        
        //一次读一个字符
        int ch;
        while ((ch=isr.read())!=-1) {
    
    
            System.out.println((char)ch);
        }
        
        //使用字符数组
        char[] chars = new char[1024];
        int len;
        while ((len = isr.read(chars))!=-1) {
    
    
            System.out.print(new String(chars));
        }
    }
}

注:字符流与字节流读写数据的方式大同小异,只是对象不同

★【经典文件复制案例】字符流复制文件

public class Test {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //字符输入流
        InputStreamReader isr = new InputStreamReader(new FileInputStream("E:\\IdeaProjects\\javatest\\a.txt"));
        //字符输出流
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("E:\\IdeaProjects\\javatest\\a-backup.txt"));

        //使用字符数组读写文件
        char[] chars = new char[1024];
        int len;
        while ((len = isr.read(chars))!=-1) {
    
    
            osw.write(chars);
        }
        osw.close();
        isr.close();
    }
}

★【经典文件复制案例——简化版】字符流复制文件

InputStreamReader与OutputStreamWriter操作起来太长了,可以使用子类FileReaderFileWriter,但是如果想解决编码问题还是要老老实实的使用父类

public class Test {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //字符输入流
        FileReader isr = new FileReader("E:\\IdeaProjects\\javatest\\a.txt");

        //字符输出流
        FileWriter osw = new FileWriter("E:\\IdeaProjects\\javatest\\a-backup.txt");

        //使用字符数组
        char[] chars = new char[1024];
        int len;
        while ((len = isr.read(chars))!=-1) {
    
    
            osw.write(chars);
        }
        osw.close();
        isr.close();
    }
}

字符缓冲流

BufferedReaderBufferedWriter

BufferedWriter有特有的方法newLine(),写入一个换行符,这个函数会调用系统默认的换行符

BufferedReader有特有的方法readLine(),读取一行文字,如果达到末尾则返回null

★【经典文件复制案例】使用字符缓冲流

public class Test {
    
    
    public static void main(String[] args) throws IOException {
    
    
        //读
        BufferedReader reader = new BufferedReader(new FileReader("E:\\IdeaProjects\\javatest\\a.txt"));
        //写
        BufferedWriter writer = new BufferedWriter(new FileWriter("E:\\IdeaProjects\\javatest\\a-backup.txt"));

        //使用字符数组
        char[] chars = new char[1024];
        int len;
        while ((len = reader.read(chars))!=-1) {
    
    
            writer.write(chars);
        }
        reader.close();
        writer.close();
    }
}

★【常用】使用字符缓冲流特有功能复制

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

        BufferedReader reader = new BufferedReader(new FileReader("E:\\IdeaProjects\\javatest\\a.txt"));
        BufferedWriter writer = new BufferedWriter(new FileWriter("E:\\IdeaProjects\\javatest\\a-backup.txt"));
        
        //使用字符数组
        String line;
        while ((line = reader.readLine())!=null) {
    
    
            writer.write(line);
            writer.newLine();
        }
        reader.close();
        writer.close();
    }
}

IO总结

什么是输入与输出

输入简单来说就是,是针对程序或者内存来说的,就是从外界读取,可以是从文件中,或者是网络请求中

输出简单来说就是,是针对程序或者内存来说的,将已经读取到的或者输入的信息写入外部文件中

几个IO操作类

字节流:

类名 功能
InputStream 所有字节输入流的超类
OutputStream 所有字节输出流的超类
FileInputStream 常用的字节输入流
FileOutputStream 常用的字节输出流
BufferedInputStream 字节输入缓冲流
BufferedOutputStream 字节输出缓冲流

字符流:

类名 功能
Reader 所有字符输入流的超类
Writer 所有字符输出流的超类
InputStreamReader 常用的字符输入流
OutputStreamWriter 常用的字符输出流
FileReader 常用的字符输入流——简化版
FileWriter 常用的字符输出流——简化版
BufferedReader 字符输入缓冲流
BufferedWriter 字符输出缓冲流

使用字节/字符数组读写的套路

char[] chars = new char[1024];
int len;
while ((len = isr.read(chars))!=-1) {
    
    
    osw.write(chars);
}

特殊操作流

标准输入流:System.in

public class Test {
    
    
    public static void main(String[] args) throws IOException {
    
    
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        //Java封装了一个类实现键盘录入,方便我们调用
        //Scanner scanner = new Scanner(System.in);
        while (true) {
    
    
            System.out.print("请输入一个字符串:");
            String line = reader.readLine();
            System.out.println("你输入的是:"+line);
        }
    }
}

标准输出流:System.out

public class Test {
    
    
    public static void main(String[] args) throws IOException {
    
    
        PrintStream out = System.out;
        out.println("hello,这里换行");
        out.print("oh,不换行");
        out.print("oh,不换行");
    }
}

字节打印流:PrintStream,继承OutputStream,只负责输出数据,有自己独有的方法

public class Test {
    
    
    public static void main(String[] args) throws FileNotFoundException {
    
    
        PrintStream ps = new PrintStream("E:\\IdeaProjects\\javatest\\ps.txt");
        //使用字节输出流的形式写到文件,是a
        ps.write(97);
        //使用特有的方法写入文件,看到的就是97
        ps.println(97);
        //ps.print(99);不换行
    }
}

字符打印流:PrintWriter

public class Test {
    
    
    public static void main(String[] args) throws FileNotFoundException {
    
    
        //如果后面加了true,会自动刷新缓冲区
        PrintWriter ps = new PrintWriter("E:\\IdeaProjects\\javatest\\ps.txt");
        //字符流的形式写到文件,是a
        ps.write(97);
        ps.write("\r\n");
        ps.flush();
        //使用特有的方法写入文件,看到的就是97
        ps.println(97);
        ps.flush();
    }
}

对象序列化流:ObjectOutputStream,需要对象实现Serializable接口,但不需要重写任何方法

public class Student implements Serializable {
    
    
    private int age;
    private String name;

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

    public static void main(String[] args) throws IOException {
    
    
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:\\IdeaProjects\\javatest\\a.txt"));
        oos.writeObject(new Student(10,"小黑"));
        oos.close();
    }
}

对象反序列化流:ObjectInputStream,可以反序列化ObjectOutputStream序列化之后的对象,需要对象实现Serializable接口

public class Student implements Serializable {
    
    
    private int age;
    private String name;

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

    public static void main(String[] args) throws IOException, ClassNotFoundException {
    
    
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:\\IdeaProjects\\javatest\\a.txt"));
        Object object = ois.readObject();
        Student student = (Student) object;
        System.out.println(student.name+":"+student.age);
    }
}

猜你喜欢

转载自blog.csdn.net/m0_46521785/article/details/114704908