【Java开发语言 10】第十章 IO (java.io.File类的使用+IO原理及流的分类+文件流+缓冲流+转换流+标准输入/输出+打印流+数据流+对象流+随机存取文件流)

第十章 IO

1 java.io.File类的使用(计算机操作系统中的文件和文件夹)

1.File类概述

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

File类只能操作文件本身,不能操作文件内容。类似于你可以把一个日记本放在各种地方,但不能在日记本中写日记

2.使用举例

  • 创建要操作的目录和文件
    在D盘D:\MyAll\study\WorkSpace的test文件夹里建立一个abc文件夹,在里面建立一个tt.txt
    在这里插入图片描述
    在这里插入图片描述
    • 访问文件名
import java.io.File;
/**
 * Created with IntelliJ IDEA.
 *
 * @Author: xuexuezi
 * @Date: 2022/11/27/0:22
 * @Description:
 */
public class FileTest {

    public static void main(String[] args) {

        //=======================================创建文件或目录对象============================================
        File f = new File("D:\\MyAll\\study\\WorkSpace\\test\\abc\\tt.txt");//这个对象f就是tt.txt了。一个参数路径的写法

        File f1 = new File("D:\\MyAll\\study\\WorkSpace","test\\abc\\tt.txt");//这个也是tt.txt。这种两个参数路径的写法使用较少,
        File f2 = new File("D:/MyAll/study/WorkSpace/test/abc/tt.txt");
        File f3 = new File("D:/MyAll\\study/WorkSpace"+File.separator+"test/abc/tt.txt");//也可以用File.separator分隔;这里试了一下,双斜杠和反斜杠混着用也没问题
        //注意,这个\斜杠在文件中是一个路径的分隔符,但是在java编程中,一个\代表转义符,在java中是用双斜杠\\或者一个/反斜杠分隔目录


        File ff = new File("D:\\MyAll\\study\\WorkSpace\\test\\abc");//一个目录
        File fs = new File("src/qxcto/chapter10/Test.java");//使用相对路径来创建File对象
        

        //====================================访问文件名=================================

        //--------------------------------getName()获取当前文件名或目录名称----------------------------------
        System.out.println(f.getName());//tt.txt
        System.out.println(fs.getName());//Test.java
        System.out.println(ff.getName());//abc

        //----------------------------------getPath()获取文件或目录的路径----------------------------------
        //获取的是new file时写的路径
        System.out.println(f.getPath());//D:\MyAll\study\WorkSpace\test\abc\tt.txt
        System.out.println(fs.getPath());//src\Test.java
        System.out.println(ff.getPath());//D:\MyAll\study\WorkSpace\test\abc

        //返回一个用当前文件的绝对路径构建的file对象
        //获取当前文件的绝对路径,若不是则补齐
        System.out.println(f.getAbsoluteFile());//D:\MyAll\study\WorkSpace\test\abc\tt.txt
        System.out.println(fs.getAbsolutePath());//D:\MyAll\study\WorkSpace\IDEA_Project\22-11-17(十、IO)\src\Test.java
        System.out.println(ff.getAbsoluteFile());//D:\MyAll\study\WorkSpace\test\abc

        System.out.println(fs);//src\Test.java;与fs.getAbsoluteFile()是一个东西,只不过一个是相对路径一个绝对路径


        //返回当前文件或文件夹的父级路径
        System.out.println(f.getParent());//D:\MyAll\study\WorkSpace\test\abc
        System.out.println(fs.getParent());//src\qx\chapter10
        System.out.println(ff.getParent());//D:\MyAll\study\WorkSpace\test

        //-------------------------------重命名文件名或目录名-------------------------------
        //重命名成功返回true,失败返回false
        //失败一般是因为原文件(夹)不存在,或新文件已存在。如果不在一个目录下重命名,要保证父级路径存在

        //把f对应的tt.txt文件重命名为tt1.txt
        System.out.println(f.renameTo(new File("D:\\MyAll\\study\\WorkSpace\\test\\abc\\tt1.txt")));//true
        //把fs对应的Test.java文件重命名为TestFile.java;不知道是不是因为本类与Test类在同一个包下
        //System.out.println(fs.renameTo(new File("src\\qxcto\\chaptet10\\Test1.java")));//false修改失败
         System.out.println(fs.renameTo(new File("D:\\MyAll\\study\\WorkSpace\\IDEA_Project\\ten_IO\\src\\qxcto\\chapter10\\Test2.java")));//true修改成功
        //把ff对应的abc路径重命名为abcabc
        System.out.println(ff.renameTo(new File("D:\\MyAll\\study\\WorkSpace\\test\\abcabc")));//true

    }

}

renameTo (重命名成功返回true,失败返回false)
参考Java file类中的renameTo方法

修改成功
在这里插入图片描述

  • 问题1:对于fs这个相对路径的文件,且与当前main方法所在类在同一个包下的类文件却无法重命名成功,重命名的新名字得是绝对路径,重命名该类名成功后,内容中的class Test{依旧未改,需要手动改
    在这里插入图片描述
    很坑…
  • 问题2:

再次重命名目录时失败,但之前一直是成功?(原因,要重命名的目录下文件关掉后有进程残余,很奇怪该文件夹中只有一个txt文件和一张png图片,手动右键+M也是改不掉。重启电脑后再重命名就成功了)
在这里插入图片描述

    • 文件检测
//=======================================文件检测=======================================

        //重命名后原File对象不存在了
        System.out.println(f.exists());//false
        System.out.println(fs.exists());//true
        System.out.println(ff.exists());//false

        //判断文件是否存在,存在返回true,不存在返回false
        System.out.println(f.exists());//true
        System.out.println(fs.exists());
        System.out.println(ff.exists());

        //判断文件是否可读,是否可写;可以返回true,不可返回false
        System.out.println(f.canWrite());//true
        System.out.println(f.canRead());

        //判断File对象是否是文件;是否是文件夹
        System.out.println(f.isFile());//true
        System.out.println(ff.isDirectory());


        System.out.println(f.lastModified());//获取文件的最后修改时间,返回的是一个毫秒数
        System.out.println(f.length());//返回文件的长度,单位是字节数
    • 文件相关操作
File f4 = new File("D:\\MyAll\\study\\WorkSpace\\test\\abc\\tt2.txt");
        System.out.println(f4.exists());
//        if(!f4.exists()) {//判断如果f4不存在
//            try {
//                f4.createNewFile();//创建新的文件
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
//        }

        f4.delete();//删除文件

    • 目录相关操作
//====================================目录相关操作========================================
        //-------------------------------------创建目录-------------------------------------
        File f5 = new File("D:\\MyAll\\study\\WorkSpace\\test\\cc");
        f5.mkdir();//创建单层目录,如果使用这样的方法来创建多层目录,就得一层一层的执行mkdir方法
        File f6 = new File("D:\\MyAll\\study\\WorkSpace\\test\\cc\\dd");
        f6.mkdir();

        File f7 = new File("D:\\MyALL\\study\\WorkSpace\\test\\a\\b\\c");//aa\bb\cc不存在
        f7.mkdirs();//创建多层目录

        //-----------------------------------返回目录的子集-----------------------------------------
        File f8 = new File("D:\\MyALL\\study\\WorkSpace\\test");
        System.out.println(f8.list());//null//返回值是一个String字符串

        String[] f8s = f8.list();//返回的是当前文件夹的子集的名称,包括目录和文件
        for(String s: f8s){
            System.out.println(s);

        }

        File[] f8ss = f8.listFiles();//返回当前文件夹子集的file对象,包括目录和文件
        for(File fss: f8ss){
            System.out.println(fss);
        }

创建多层目录

在这里插入图片描述

f8.list()结果,返回的是子文件或目录名称,为String类

在这里插入图片描述

f8.listFiles()结果,返回的是子文件或目录,为File类

在这里插入图片描述

✔ 练习:遍历目录下所有文件和目录

遍历D盘下的test文件,把test文件夹下所有的目录与文件全部遍历出来,不论层级有多深,要全部遍历出来

思路:类似于递归思路遍历。每遍历到一个目录就判断其下是否为空,不为空则进入目录遍历。为空则继续遍历下一项

import java.io.File;

/**
 * Created with IntelliJ IDEA.
 * @Author: xuexuezi
 * @Date: 2022/11/27/0:22
 * @Description: 小测试,遍历test下的所有目录与文件。用到递归思路
 */
public class Test {

    public static void main(String[] args) {

        new Test().test(new File("D:\\MyAll\\study\\WorkSpace\\test"));
    }

    
    /**
    * @Description: 递归遍历文件
    * @Param: [file]
    * @return: void
    */
    public void test(File file){//处理一个file对象,如果是文件直接输出,如果是目录则遍历目录下子文件和子目录
        //先判断这个File对象是文件还是目录
        if(file.isFile()){//是文件直接输出名称
            System.out.println(file.getAbsoluteFile()+"是文件");
        }else{//是目录则遍历目录下的file对象,并调用自身test方法再次处理子file对象
            System.out.println(file.getAbsoluteFile()+"是目录");

            //如果是文件夹(目录),内部可能有子文件夹或者文件
            File[] fstr = file.listFiles();
            //优化一下,当目录下为空(如果file是文件则file.listFiles返回null),或长度为0时(file为空目录则返回空数组,长度为0)不处理(文件夹的长度会比其下文件长度长一点点)
            if(fstr != null && fstr.length>0){
                for(File f:fstr){
                    test(f);//递归,调用方法自身去处理该目录下的子文件or子目录
                }
            }

        }
    }


}


在这里插入图片描述

2 IO原理及流的分类(IO指input和output)

流是什么?IO流原理
例如通过程序把一个图放到某一个文件夹,要怎么完成,把图片转化成一个数据集(例如二进制),把这些数据一点一点传到文件件。这个传递的过程很类似于水的流动,我们就可以称这个整体的数据集是一个数据流。

流的分类分为两种,一个是文件流一个是缓冲流。

  • 文件流都是File开头,数据流的读写都是基于文件的操作。
  • 缓冲流Buffered开头,数据流的读写是基于内存的操作。

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

输入流和输出流

  • 输入流必须保证,要读取的文件存在,否则出异常
  • 输出流,在写入一个文件时,如果目录下有同名文件将被覆盖

字符流和字节流

  • 字节流以字节(1 byte字节 == 8bit比特)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。ASCII 码中,一个英文字母字符(不分大小写)为一个字节,一个中文汉字字符为两个字节。
  • 字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。

总结输入输出的数据类型:

字节输入时,按byte数组接收

byte[] b = new byte[1024];
len = bfin.read(b)

字节输出时,按byte数组输出

String str = "哈哈,hello,barbie,把这段话输出";
bfout.write(str.getBytes());

字符输入时,用char数组接收

char[] ch = new char[20];
len = fr.read(ch)

字符输出时,可以用String类输出;也可以是char数组, 3个参数的形式

//参数String text
 fw.write(text);
char[] ch = new char[200];
len = fr.read(ch)//先读
fw.write(ch, 0, len);//再写

在这里插入图片描述

3 文件流

FileInputStream/FileOutputStream

  • 输入流用到的方法
FileInputStream in = new FileInputStream("D:\\MyAll\\study\\WorkSpace\\test\\hah.txt");

✔ 方法.read(b);//b在字符流中为char数组,字节流中为byte数组

in.read(b);//b为btye数组,负责接收in的数据,若读完则返回-1。测试发现如果b数组长度大于数据长度,该方法都是一次读完数据,返回所读数据的长度。如果b长度小于数据长度,需要循环读取会一直刷新b数组的内容,一段一段的读,每次都读够数组长度,如果是中文则会乱码,因为一个中文汉字由两个字节构成;而一个英文字母不论大小写都由一个字节构成。
System.out.println(new String(b, 0, len));//读到数组b内输出,new String(b)j将b数组转化为String字符串,并且0为开始转化位置,len为结束转化位置
in.close();//流在使用完毕后,一定要关闭

  • 输出流用到的方法

//outFile开始时不存在,输出后自动生成;如果开始时outFile存在,则刷新文件内容

   FileOutputStream out = new FileOutputStream("D:\\MyAll\\study\\WorkSpace\\test\\outFile.txt");

✔ 方法.write(str.getBytes()); .write(str); .write(ch,0,len);//str表示要输出的文本为String类型,ch为char数组。其中字节流输出时必须为byte数组,字符流可以是char数组和String

out.write(str.getBytes());//把数据写到内存,可以看到文件内容变化
//str.getBytes()将String字符串str转化为byte类型的数组并返回
out.flush();//把内存中的数据刷写到硬盘。目前不会观测效果
out.close();//关闭流

import java.io.FileInputStream;
import java.io.FileOutputStream;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: xuexuezi
 * @Date: 2022/12/02/20:35
 * @Description: 文件流
 */
public class FileStreamTest {
    public static void main(String[] args) {
        FileStreamTest.testFileInputStream();
        FileStreamTest.testFileOutputStream();


    }


    /**
    * @Description: 文件字节输入流
    * @Param: []
    * @return: void
    */
    public static void testFileInputStream() {

        //==========================================FileInputStream========================================

        //io操作都是有异常的,需要捕获或者抛出
        try {
            FileInputStream in = new FileInputStream("D:\\MyAll\\study\\WorkSpace\\test\\hah.txt");//必须要是存在的文件
            //InputStream为字节流,做一个比特数组用来接收数据

            byte[] b = new byte[10];//设置一个byte数组,接收读取的文件的内容
            int len = 0;//设置一个读取数据的长度

            /*该方法会有一个返回值,返回值是读取的数据的长度,如果读取到最后一个数据,还会向后读一个,这个时候返回值就是-1
            也就意味着当in.read(b)的返回值是-1的时候,整个文件就读取完了
            in.read(b);//b数组接收in的输入字节流 */

            //注意:new String三个参数的用法(要转化为String类的数组名,开始转化位置,转化结束位置)
            while ((len = in.read(b)) != -1) {//说明没读完
                System.out.println(len);//0//因为疑惑in.read的返回值,发现此处while和if没有区别。第一次返回值即为数据长度(原因,因为数据太短)
                //只读取刚好完即可,不会多读
                System.out.println(new String(b, 0, len));

                /*?一个疑惑:循环输出与单句输出的内容完全一致,解决:是因为数据太短,
                当数据比较长时,每次read都会新读进来一段存到b然后根据[0,len]输出。而且读满的情况下len是固定的长度10
                //例1输出:
                5
                qjhfu

                例2输出:
                10
                把这个�
                10
                ��件的�
                10
                �容输入
                10
                到计算�
                2
                ��
                */


            }

            //优化前,固定b数组长度,可能会比要读取的文件内容长。
            //new String一个参数的用法(要转化为String的数组名)
            //System.out.println(new String(b));//输出b数组,并转为String类型

            in.close();//注意:流在使用完毕之后一定要关闭

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

    }


    /**
     * @Description: 文件字节输出流
     * @Param: []
     * @return: void
     */
    public static void testFileOutputStream() {
        //=========================FileOutputStream============================================
        try{
            //outFile开始时不存在,输出后自动生成;如果开始时outFile存在,则刷新文件内容
            FileOutputStream out = new FileOutputStream("D:\\MyAll\\study\\WorkSpace\\test\\outFile.txt");
            String str = "2把这段文字输出到outFile文件";
            out.write(str.getBytes());//把数据写到内存,可以看到文件内容变化
            out.flush();//把内存中的数据刷写到硬盘。目前不会观测效果
            out.close();//关闭流

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

    }


}

✔ 练习:编写程序,把一个文件复制到指定的文件夹下

  • 注意:文件字节流非常通用,可以用来操作字符的文档,还可以操作任何的其他类型文件(图片、压缩包等 ),因为字节流直接使用二进制
 public static void main(String[] args) {

        //复制文件到一个文件夹下
        File file1 = new File("D:\\MyAll\\study\\WorkSpace\\test\\abc\\img.png");
        File file2 = new File("D:\\MyAll\\study\\WorkSpace\\test\\cc");
        new Test().copyFile(file1,file2);


    }

 /**
 * @Description: 把一个文件复制到指定的文件夹下,file1为该文件,file2为该目录
 * @Param: [file1, file2]
 * @return: void
 */
    public void copyFile(File file1, File file2){
        if (file1.isFile() && file2.isDirectory()) {
            //通过文件字节流复制其内容
            //思路,将文件内容读取到内存,用一个byte数组接收,再将其输出到指定路径下,将自动创建新文件
            try {
                FileInputStream in = new FileInputStream(file1);//把file1的内容输入进来,读的源文件
                //输出到新路径下
                FileOutputStream out = new FileOutputStream(file2 + File.separator + file1.getName());//复制到哪里


                byte[] b = new byte[200];//做大一点,因为b作为接收对象必须接收所有数据,不可以比文件中数据长度短
                int len = 0;

                while ((len = in.read(b)) != -1) {
                    System.out.println(new String(b, 0, len));//输出一下要复制的数据
                    out.write(b);//如果b长度小于数据长度,可能会读不全。直接在循环里交互,即使短也能按段复制

                }

                out.flush();//把写到内存的数据刷到硬盘
                out.close();//后开的先关
                in.close();


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

        }
        else{
            System.out.println("输入错误,请重新输入。请保证file1为文件,file2为目录。该方法用来将file1复制到file2下");
            return;
        }
        
    }

在这里插入图片描述

在这里插入图片描述

FileReader/FileWriter

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

  • 字符流只适合操作内容是字符的文件例如txt文档
import java.io.FileReader;
import java.io.FileWriter;
/**
 * Created with IntelliJ IDEA.
 *
 * @Author: xuexuezi
 * @Date: 2022/12/03/23:10
 * @Description: 文件字符流
 */
public class FileRWTest {

    public static void main(String[] args){

        FileRWTest.testFileReader("D:\\MyAll\\study\\WorkSpace\\test\\FileReader.txt");//FileReader.txt开始时存在
        FileRWTest.testFileWriter("把这段字符输出到Filewriter。txt","D:\\MyAll\\study\\WorkSpace\\test\\FileWriter.txt");//FileWriter.txt开始时不存在

    }

    public static void testFileReader(String inPath){
        try{
            FileReader fr = new FileReader(inPath);
            char[] ch = new char[20];

            int len = 0;
            while((len = fr.read(ch)) != -1){
                System.out.println(new String(ch, 0, len));
            }

            fr.close();

        }catch(Exception e){

        }



    }

    public static void testFileWriter(String text, String outPath){

        try{
            FileWriter fw = new FileWriter(outPath);
            fw.write(text);//写到内存中
            fw.flush();//把内存中数据刷写到硬盘
            fw.close();//关闭流

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

  • 拷贝文件,顺便可以重命名
 	public static void main(String[] args){

        FileRWTest.copyFile("D:\\MyAll\\study\\WorkSpace\\test\\cc\\dd\\文件.txt","D:\\MyAll\\study\\WorkSpace\\test\\abca\\新文件.txt");

    }
    
    public static void copyFile(String oldFile, String newFile){
        try{
            FileReader fr = new FileReader(oldFile);
            FileWriter fw = new FileWriter(newFile);

            char[] ch = new char[200];//字符数组接收读到的数据
            int len = 0;
            while((len = fr.read(ch)) != -1){
                fw.write(ch, 0, len);//把读到的数据按照字符格式输出
            }
            fw.flush();
            fw.close();
            fr.close();

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

在这里插入图片描述

在这里插入图片描述

注意:
定义文件路径时,注意:可以用“/”或者“\”。
在写入一个文件时,如果目录下有同名文件将被覆盖。
在读取文件时,必须保证文件已存在,否则出异常。

4 处理流1:缓冲流

BufferedInputStream/BufferedOutputStream

在这里插入图片描述

  • 缓冲字节输入/输出流
package qxcto.chapter10;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: xuexuezi
 * @Date: 2022/12/04/0:42
 * @Description: 缓冲字节流
 */
public class BufferedStreamTest {

    public static void main(String[] args){

        //因为两个方法都把可能的异常抛出了,调用的时候需要接收一下
        try{
            BufferedStreamTest.testBufferedInputStream();

            BufferedStreamTest.testBufferedOutputStream();

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

      
    }

    /**
    * @Description: 缓冲字节输入流
    * @Param: []
    * @return: void
    */
    public static void testBufferedInputStream() throws Exception {
        //文件字节输入流对象
        FileInputStream fin  = new FileInputStream("D:\\MyAll\\study\\WorkSpace\\IDEA_Project\\ten_IO\\src\\qxcto\\chapter10\\inTt.txt");

        //缓冲字节输入流对象
        //把这个文件字节流放入到这个缓冲输入流当中
        BufferedInputStream bfin = new BufferedInputStream(fin);//参数需要一个InputStream的或者其子类的对象
        byte[] b = new byte[1024];
        int len = 0;
        while((len = bfin.read(b)) != -1){
            System.out.println(new String(b, 0 ,len));
        }

        //关闭流的时候,本着一个最晚开的最早关,依次关
        bfin.close();//后开的先关,一个嵌套样式
        fin.close();

    }

    /**
    * @Description: 缓冲字节输出流
    * @Param: []
    * @return: void
    */
    public static void testBufferedOutputStream() throws Exception{
        //创建字节输出流对象
        FileOutputStream fout = new FileOutputStream("D:\\MyAll\\study\\WorkSpace\\IDEA_Project\\ten_IO\\src\\qxcto\\chapter10\\outTt.txt");

        //创建字节输入流对象
        BufferedOutputStream bfout = new BufferedOutputStream(fout);

        String str = "哈哈,hello,barbie,把这段话输出";
        bfout.write(str.getBytes());//写到内存中
        bfout.flush();//刷到硬盘上

        bfout.close();
        fout.close();
    }

    
}

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

  • 复制文件到新路径下
	public static void main(String[] args) {
    	BufferedStreamTest.bfSCopyFile("D:\\MyAll\\study\\WorkSpace\\test\\abca.zip","D:\\MyAll\\study\\WorkSpace\\test\\haha\\wex\\abcaCopy.zip");
	}
 


/**
* @Description: 缓冲字节流复制文件
* @Param: oldFile 原文件的原路径;输入的内容
* @Param newFile 要复制到的新路径,还可以顺便改名字;输出的内容
* @return: void
*/
    public static void bfSCopyFile(String oldFile, String newFile){
        try{

            BufferedInputStream bfin = new BufferedInputStream(new FileInputStream(oldFile));

            BufferedOutputStream bfout = new BufferedOutputStream(new FileOutputStream(newFile));

            byte[] by = new byte[1024];
            int len = 0;
            System.out.println("打印一下读到的内容");
            while((len = bfin.read(by)) != -1){
                System.out.println(by);
                bfout.write(by, 0 , len);//写到内存
            }

            bfout.flush();//刷到硬盘

            bfout.close();
            bfin.close();


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

在这里插入图片描述

在这里插入图片描述

BufferedReader/BufferedWriter

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: xuexuezi
 * @Date: 2022/12/04/0:43
 * @Description: 缓冲字符流
 */
public class BufferedRWTest {
    public static void main(String[] args){

        try {
            BufferedRWTest.testBufferedReader("D:\\MyAll\\study\\WorkSpace\\test\\FileReader.txt");
            BufferedRWTest.testBufferedWriter("缓冲字符流进行输出", "D:\\MyAll\\study\\WorkSpace\\test\\FileWriter.txt");
        }catch(Exception e){
            e.printStackTrace();
        }
    }

    /**
    * @Description: 缓冲字符输入流
    * @Param: inPath
    * @return: void
    */
    public static void testBufferedReader (String inPath)throws Exception{

        BufferedReader bfR = new BufferedReader(new FileReader(inPath));
        char[] ch = new char[1024];
        int len = 0;
        while((len = bfR.read(ch)) != -1){
            System.out.println(new String(ch, 0, len));
        }

        bfR.close();
    }
    
    /**
    * @Description: 缓冲字符输出流
    * @Param: text
    * @Param outPath
    * @return: void
    */
    public static void testBufferedWriter(String text, String outPath)throws Exception{

        BufferedWriter bfW = new BufferedWriter(new FileWriter(outPath));

        bfW.write(text);
        bfW.flush();
        bfW.close();
    }
}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 缓冲字符流复制文件
public static void main(String[] args){
   try {
       BufferedRWTest.copyBfRW("D:\\MyAll\\study\\WorkSpace\\test\\cc\\dd\\文件.txt","D:\\MyAll\\study\\WorkSpace\\test\\abcabc\\新文件.txt");
   }catch(Exception e){
       e.printStackTrace();
   }
}

/**
 * @Description: 缓冲字符流复制文件
 * @Param: oldFile
 * @Param newFile
 * @return: void
 */
    public static void copyBfRW(String oldFile, String newFile) throws Exception{ 
    
        BufferedReader bfR = new BufferedReader(new FileReader(oldFile));
        BufferedWriter bfW = new BufferedWriter(new FileWriter(newFile));

        char[] ch = new char[1024];
        int len = 0;
        while((len = bfR.read(ch)) != -1){
            bfW.write(ch, 0 ,len);
        }

        bfW.flush();

        bfW.close();
        bfR.close();
    }
}

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

5 处理流2:转换流(InputStreamReasder/OutputStreamWriter)

可以把字节流转换成字符流。
当字节流中的数据都是字符的时候,使用转换流转为字符流处理

在这里插入图片描述

  • 查看项目编码
    在这里插入图片描述

  • 查看类编码格式
    在这里插入图片描述

  • 转换输入流

public static void main(String[] args){
        //所有的文件都是又编码格式的
        //对于我们来说,txt和java文件一般来讲有三种编码
        //ISO8859-1,西欧编码,是纯粹英文编码,不适用汉字
        //GBK和UTF-8,这两编码是适用于中文和英文
        //我们一般使用UTF-8这种编码

        try{
            StreamRWTest.testInputStreamReader();
            
        }catch(Exception e){
            e.printStackTrace();
        }


    }

    /**
     * 转换输入流
     * 把字节流转换成字符流
    */
    public static void testInputStreamReader() throws Exception{
        FileInputStream fin = new FileInputStream("D:\\MyAll\\study\\WorkSpace\\IDEA_Project\\ten_IO\\src\\qxcto\\chapter10\\tt5.txt");
        //将字节流转换成字符流
        InputStreamReader inR= new InputStreamReader(fin,"UTF-8");//参数1是字节流,参数2是编码

        char[] ch = new char[100];//因为转换成字符流,用char数组接收
        int len = 0;
        while((len = inR.read(ch)) != -1){
            System.out.println(new String(ch, 0, len));
        }

        inR.close();
        fin.close();

    }
    • 正确输出结果

在这里插入图片描述

    • 错误输出结果

如果转换时参数2的编码不对应文件的编码格式

在这里插入图片描述

  • 转换输出流
public static void main(String[] args){
        //所有的文件都是又编码格式的
        //对于我们来说,txt和java文件一般来讲有三种编码
        //ISO8859-1,西欧编码,是纯粹英文编码,不适用汉字
        //GBK和UTF-8,这两编码是适用于中文和英文
        //我们一般使用UTF-8这种编码

        try{
            StreamRWTest.testOutputStreamWriter();
            
        }catch(Exception e){
            e.printStackTrace();
        }


    }

    /*
    *转换输出流
    * 把字节流转换为字符流
     */

    public static void testOutputStreamWriter() throws Exception{
        //该路径当前不存在,第一次输出自动创建,因为项目设置编码格式为UTF-8,能确定创建tt6.txt后也为UTF-8编码格式
        FileOutputStream fout = new FileOutputStream("D:\\MyAll\\study\\WorkSpace\\IDEA_Project\\ten_IO\\src\\qxcto\\chapter10\\tt6.txt");
        OutputStreamWriter outW = new OutputStreamWriter(fout,"GBK");

        String str = "输出到tt6.txt";
        outW.write(str);
        outW.flush();

        outW.close();
        fout.close();

    }
    • 正确输出结果

在这里插入图片描述

    • 错误输出
      文件本身为UTF-8的编码格式,转换时参数2提供为GBK格式,则输出乱码

在这里插入图片描述
此时再讲tt6.txt改为GBK

在这里插入图片描述
刚改完输出就正常,无需运行
在这里插入图片描述

6 处理流3:标准输入/输出流

在这里插入图片描述

✔ 方法 .readLine();//是字符流的方法

该方法是字符流的方法,
与.read(b)的区别在于:
1.使用方

  • 字符流和字节流都可以使用.read();
  • 目前只见过BufferedReader的对象使用readLine(),且缓冲字符输入流接收了标准输入流

2.输入数据的过程

  • 字符流.read(char数组);字节流.read(byte数组);//是将流里的数据输入到数组中,一个字符(字节)的读
  • str = BufferedReader.read();是将缓冲流中的数据传入str,一行一行的读

3.返回值

  • .read(b)的返回值是一个int长度,表示读取到的数据长度。读到最后一个数据的后一位返回-1表示读取结束。受制于接收的数组长度,如果数组长度大于数据长度,读一次就可读完,但如果数组长度比较短,就需要循环读,且每次读到的数据长度(除过最后一次)都等于数组长度。为了防止读多,一般接收这个返回值len作为输出时的长度,将用new String(b, 0, len)来输出数组中的数据。
  • .readLine()的返回值是一个String字 符串为读到的数据,一行一行读,每次都用str接收一下,也是循环接收。直到读到最后一个最后一个字符之后的下一个,就是空null。

例1:bfR为接收了标准输入的缓冲字符输入流

 		String str = "";//定义一个临时接收数据的字符串
        //.readLine返回的是一个字符串,如果要是读到最后一个最后一个字符之后的下一个,就是空null
        while((str = bfR.readLine()) != null){
            System.out.println(str);
        }

在这里插入图片描述

在这里插入图片描述

✔ 练习:1.把控制台输入的内容写到指定的txt文件中,当接收到字符串over,就结束程序的运行。

复习equals == :

  • ==对于基础数据比较内容,对于引用类只有同一个对象才true
  • equals只能比较对象,只有对于File,String,Data和包装类是比较内容,不要求是同一个对象。其他类都是必须为同一个对象才相等true
public static void main(String[] args){
        try{
            //控制台输入的数据输出到该txt文件,开始时不存在
            Test3.testSystemIn("D:\\MyAll\\study\\WorkSpace\\IDEA_Project\\ten_IO\\src\\qxcto\\chapter10\\systemIn.txt");
        }catch(Exception e){
            e.printStackTrace();
        }
    }


    /*控制台输入的内容写到指定的txt文件中,当接收到字符串over,就结束程序的运行
    *
     */
    //我的写法:理解怎么使用标准输入流来接收控制台输入的内容,开始想使用字节流但发现readLine方法只能是字符流用
    //全篇使用字符流(为什么呢,因为readLine是字符流的方法),用缓冲字节输出流接收新建一个文件字节输出流来确认输出txt的路径,再用缓冲字节输入流接收标准输入流
    //定义String空字符串作为一个临时接收字符串的变量
    //while读,读到null说明读完,循环体内写
    
    public static void testSystemIn(String txtPath)throws Exception{

        //创建一个输入转换流,把标准输入转为字符流
        InputStreamReader inR = new InputStreamReader(System.in);
        //创建一个缓冲字节输入流,把输入流放入缓冲流
        BufferedReader bfR = new BufferedReader(inR);

        创建一个缓冲字节输出流,用来接收到数据后输出到txt文件,缓冲流接收一下文件字节输出流会快一点
        BufferedWriter bfOut = new BufferedWriter(new FileWriter(txtPath));

        String line ="";//定义一个临时接收字符的字符串,而且是一行一行的读
        //这里需要考虑实现读到over结束字符
        //复习:== 对于基础数据比较内容,对于引用类只有同一个对象才true
        //equals只能比较对象,只有对于File,String,Data和包装类是比较内容,不要求是同一个对象。其他类都是必须为同一个对象才相等true

        while((line = bfR.readLine()) != null){
            if(line.equals("over")){
                //中断逻辑
                break;
            }
            //读取的每一行都写到指定的txt文件中
            bfOut.write(line);
        }

        bfOut.flush();

        bfOut.close();
        bfR.close();
        inR.close();

    }

在这里插入图片描述

✔ 练习 2.在一个txt文件中,写一组用户名和密码,通过控制台输入用户名和密码,与txt文件中的用户名和密码做对比,如果一样就在控制台打印登陆成功,如果不一致就打印用户名或密码错误。

/*练习2:在一个txt文件中,写一组用户名和密码,通过控制台输入用户名和密码,
    与txt文件中的用户名和密码做对比,如果一样就在控制台打印登陆成功,如果不一致就打印用户名或密码错误。*/
    //
    public static void testPass(String txtPath) throws Exception{
        //创建一个转换流,转换标准输入为字符流
        InputStreamReader inR = new InputStreamReader(System.in);
        //创建一个缓冲输入流,接收控制台的输入
        BufferedReader bfR = new BufferedReader(inR);
        //接收txt文件的输入
        BufferedReader bfRtxt = new BufferedReader(new FileReader(txtPath));

        String line = "";//一个字符串临时接收一下控制台输入的每行的字符串
        String linetxt = "";//一个字符串临时接收一下从txt输入的每行的字符串

        //循环两次,接收两行数据
        boolean bf = true;//定义一个判断是否登录成功的标志,因为我们不能让他用户名一错误就break,这样没机会输入密码
        System.out.println("请输入用户名和密码,回车隔开");
        for(int i=0; i<2; i++){

            line = bfR.readLine();
            linetxt = bfRtxt.readLine();

            if(! line.equals(linetxt)){
                bf = false;
            }
        }
        if(bf == true){
            System.out.println("登陆成功");
        }else{
            System.out.println("用户名或密码错误");
        }

        bfRtxt.close();
        bfR.close();
        inR.close();
    }

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

7 处理流4:打印流(了解)

PrintStream/PrintWriter(System.out.println)

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

8 处理流5:数据流(了解)

DataInputStream/DataOutputStream

在这里插入图片描述

  • 输出流
    用数据输出流写到文件中的基本数据类型是乱码的,不能直接辨认。需要数据层的输入流来读取
public static void main(String[] args) {
        try{
            DataInOutTest.testDataOutputStream();         

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

    }

   /**
   * @return: void
   * @Param:
   * @Description: 数据输出流
    * 用数据输出流写到文件中的基本数据类型是乱码的,不能直接辨认。
    * 需要数据层的输入流来读取
    * DataOutputStream
   */
    public static void testDataOutputStream()throws Exception{
        DataOutputStream dout = new DataOutputStream(new FileOutputStream("D:\\MyAll\\study\\WorkSpace\\IDEA_Project\\ten_IO\\src\\qxcto\\chapter10\\dataInOut.txt"));//需要一个OutputStream类型的参数,子类都可以
        //dout.writeBoolean(true);
        dout.writeDouble(7.56d);
        //dout.writeInt(345);

        dout.flush();
        dout.close();

    }

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

  • 输入流
      • 用数据输出流写到文件中的基本数据类型是乱码的,不能直接辨认。需要数据层的输入流来读取
      • 用数据输入流读取数据输出流写到文件中的数据时,要保证使用和当时写的数据类型一致的类型来读取
      • 也就是说,如果写的时候是writeDouble,那么读的时候就得是readDouble
public static void main(String[] args) {
        try{

            DataInOutTest.testDataOutputStream();
            DataInOutTest.testDataInputStream();

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

    }

   /**
   * @return: void
   * @Param:
   * @Description: 数据输出流
    * 用数据输出流写到文件中的基本数据类型是乱码的,不能直接辨认。
    * 需要数据层的输入流来读取
    * DataOutputStream
   */
    public static void testDataOutputStream()throws Exception{
        DataOutputStream dout = new DataOutputStream(new FileOutputStream("D:\\MyAll\\study\\WorkSpace\\IDEA_Project\\ten_IO\\src\\qxcto\\chapter10\\dataInOut.txt"));//需要一个OutputStream类型的参数,子类都可以
        //dout.writeBoolean(true);
        dout.writeDouble(7.56d);
        //dout.writeInt(345);

        dout.flush();
        dout.close();

    }

    /**
    * @return: void
    * @Param:
    * @Description: 数据的输入流,
     * 用数据输出流写到文件中的基本数据类型是乱码的,不能直接辨认。需要数据层的输入流来读取
     * 用数据输入流读取数据输出流写到文件中的数据时,要保证使用和当时写的数据类型一致的类型来读取
     * 也就是说,如果写的时候是writeDouble,那么读的时候就得是readDouble
    */
    public static void testDataInputStream()throws Exception{
        //把刚输入的那个文件再输入一下,为了识别输出的数据,因为无法手动识别
        DataInputStream din = new DataInputStream(new FileInputStream("D:\\\\MyAll\\\\study\\\\WorkSpace\\\\IDEA_Project\\\\ten_IO\\\\src\\\\qxcto\\\\chapter10\\\\dataInOut.txt"));
        System.out.println(din.readDouble());
        din.close();
    }

在这里插入图片描述

写用writeDouble,读用readInt。则读出来不是本身的值

在这里插入图片描述
写用writeDouble,读用readBolean。则读出来不是本身的值
在这里插入图片描述

9 处理流6:对象流—涉及序列化、反序列化

ObjectInputStream/ObjectOutputStream(把一个对象转化为一个数据流进行读写)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
对象的序列与反序列化使用的类要严格一致,包名,类名,类结构等等所有都要一致。所有东西都要一致

  • 对象的序列化
public static void main(String[] args) {
        try{
            Test4.testSerialize();
        }catch(Exception e){
            e.printStackTrace();
        }

    }

    /**
     * 对象的序列化
     */
    public static void testSerialize()throws Exception{
        //定义对象的输出流,把对象序列化之后的流放到指定的文件中
        ObjectOutputStream oout = new ObjectOutputStream(new FileOutputStream("D:\\MyAll\\study\\WorkSpace\\IDEA_Project\\ten_IO\\src\\qxcto\\chapter10\\oout.txt"));

        Person p1 = new Person();
        p1.name = "张三";
        p1.age = 17;

        oout.writeObject(p1);
        oout.flush();//刷写数据到硬盘

        oout.close();

    }

在这里插入图片描述

  • 反序列化
public static void main(String[] args) {
        try{
            Test4.testSerialize();
            Test4.testDeserialize();
        }catch(Exception e){
            e.printStackTrace();
        }

    }

    /**
     * 对象的序列化
     */
    public static void testSerialize()throws Exception{
        //定义对象的输出流,把对象序列化之后的流放到指定的文件中
        ObjectOutputStream oout = new ObjectOutputStream(new FileOutputStream("D:\\MyAll\\study\\WorkSpace\\IDEA_Project\\ten_IO\\src\\qxcto\\chapter10\\oout.txt"));

        Person p1 = new Person();
        p1.name = "张三";
        p1.age = 17;

        oout.writeObject(p1);
        oout.flush();//刷写数据到硬盘

        oout.close();

    }

    /**
     * 对象的反序列化
     * @throws Exception
     */
    public static void testDeserialize()throws Exception{
        //把对象流读回来
        //创建对象输入流,从指定的文件中把对象的序列化后的流读取出来
        ObjectInputStream oin = new ObjectInputStream(new FileInputStream("D:\\MyAll\\study\\WorkSpace\\IDEA_Project\\ten_IO\\src\\qxcto\\chapter10\\oout.txt"));

        Object obj = oin.readObject();

        Person p = (Person)obj;
        //Person p = (Person)obj;
        //这个时候序列化与反序列化使用的类不是一个类,分别是qxcto.chapter10.Person和qxcto.chapter10.object.Person
        //这是反序列化就有异常qxcto.chapter10.Person cannot be cast to qxcto.chapter10.object.Person
        //类型转换异常,哪怕两个类的结构一致
        //qxcto.chapter10.object.Person p = (qxcto.chapter10.object.Person)obj;
        System.out.println(p.name);
        System.out.println(p.age);

        oin.close();
    }

在这里插入图片描述

  • 这个时候序列化与反序列化使用的类不是一个类,错误
    • 两个类的结构完全一致,但不是一个类

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

在这里插入图片描述

10 随机存取文件流

RandomAccessFile(例如一个txt文件,其中有100行数据,可以直接读取第50行的数据,也可以在第89行插入数据)

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

  • 随机读
 public static void main(String[] args) {

        try{
            RandomTest.testRandomRead();
        }catch(Exception e){
            e.printStackTrace();
        }
    }

    public static void testRandomRead() throws Exception{

        //      r: 以只读方式打开
        //      rw:打开以便读取和写入
        //      rwd:打开以便读取和写入;同步文件内容的更新
        //     rws:打开以便读取和写入;同步文件内容和元数据的更新
        //最常用的是r和rw

        //RandomAccessFile的构造有两个参数,参数1是读写的文件的路径
        //参数2是指定RandomAccessFile的访问方式
        RandomAccessFile ra = new RandomAccessFile("D:\\MyAll\\study\\WorkSpace\\IDEA_Project\\ten_IO\\src\\qxcto\\chapter10\\RandomTest.txt","r");

        //通过设置读取文件内容的起始点,来达到从文件的任意位置读取
        ra.seek(13);//设置读文件内容的起始点
        byte[] b = new byte[1024];//可见随机存取流也是字节流
        int len = 0;
        while((len = ra.read(b)) != -1){
            System.out.println(new String(b, 0, len));
        }

    }

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

  • 随机写
    • 如果是在开头或者中间的某个位置开始写的话,就会用写的内容覆盖掉等长度的原内容
public static void main(String[] args) {

        try{
            //RandomTest.testRandomRead();
            RandomTest.testRandomWriter();
        }catch(Exception e){
            e.printStackTrace();
        }
    }

    //随机写
    public static void testRandomWriter() throws Exception{
        //因为要写入,记得设置为rw可读写,如果是r只读就错了
        RandomAccessFile ra = new RandomAccessFile("D:\\MyAll\\study\\WorkSpace\\IDEA_Project\\ten_IO\\src\\qxcto\\chapter10\\RandomTest.txt","rw");

        //ra.seek(6);//设置写的起始点,0代表从头开始写
        //注意:如果是在开头或者中间的某个位置开始写的话,就会用写的内容覆盖掉等长度的原内容
        ra.seek(ra.length());//设置写的起点,ra.length()代表从文件的最后结尾写,也就是文件的追加
        ra.write("咋们在尾部追加,以免覆盖".getBytes());

        ra.close();//不用flush

    }

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

流小节

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值