美文网首页
011-文件和流的基本用法

011-文件和流的基本用法

作者: Ktry | 来源:发表于2020-03-16 09:10 被阅读0次

文件和流的基本用法

1. 文件的使用

1.1 文件的概念

简单来说,磁盘上保存的一切内容都是文件。

1.2 文件的操作
文件的表示方式:使用java.io.File类来表示。
用来判断的操作:
用来得到文件信息的操作:
用来创建删除文件的操作:
注意:File类对于文件的操作,仅仅只是对于文件本身的操作,不包含对于文件内容的操作,对于内容的操作叫做流。
1.3 File类基本创建
public static void main(String[] args) {
        // 1.直接指定路径
        File file = new File("e:"+File.separator+"1.txt");
        // 2.指定目录的名称,文件的名称
        File file2 = new File("C:/Users/admin/Desktop/aaa", "2.txt");
        // 得到父目录
        File parent = new File("C:\\Users\\admin\\Desktop\\aaa");
        // 3.指定目录,文件的名称
        File file3 = new File(parent, "3.txt");

        System.out.println(file);
        /*
        在不同的系统中,路径的分隔符不一样,windows习惯用\,linux等系统习惯用/
        在java代码中,特别是windows系统中,使用\或者/都可以,
        但是\由于本身在Java中作为转义字符使用,所以需要使用\\
        为了避免分割符造成的兼容性问题,Java中提供了应对的办法。
        推荐使用File.separator,它表示得到当前系统相关的分割符
        */

        //注意:无论提供的路径是否存在,File类都会创建成功,不会null
    }
1.4 用来判断的操作
public static void main(String[] args) {
        File file = new File("C:\\Users\\admin\\Desktop\\aaa\\3.txt");
        File otherFile = new File("C:\\Users\\admin\\Desktop\\aaa\\4.txt");
        // canExecute : 能否执行,只针对于linux之类系统有效,windows基本都返回true
        boolean b = file.canExecute();
        // 小技巧,如何执行windows中的exe文件
        /*
        try {
            Runtime runtime = Runtime.getRuntime(); // 得到执行环境
            runtime.exec("C:\\Program Files (x86)\\Tencent\\QQ\\Bin\\QQScLauncher.exe");
        } catch (Exception e) {
            e.printStackTrace();
        }
        */
        boolean b1 = file.canRead(); // 判断文件是否可读
        boolean b2 = file.canWrite(); // 判断文件是否可写

        boolean b3 = file.exists(); // 判断文件是否存在
        boolean b4 = file.isDirectory(); // 判断文件是否目录(文件夹)
        boolean b5 = file.isFile(); // 判断是否一个文件

        boolean b6 = file.isHidden(); // 判断是否隐藏
        int result = file.compareTo(otherFile); // 比较两个文件pathname,相等为0
    }
1.6 得到文件信息的操作
public static void main(String[] args) {
        File file = new File("C:\\Users\\admin\\Desktop\\aaa\\3.txt");

        String absolutePath = file.getAbsolutePath(); // 获得文件绝对路径(包含盘符)

        long totalSpace = file.getTotalSpace(); // 得到当前文件所对应磁盘空间总大小
        long freeSpace = file.getFreeSpace(); // 得到当前文件所对应磁盘空间剩余空间大小
        long usableSpace = file.getUsableSpace(); // 得到当前文件所对应磁盘空间可用空间大小

        String name = file.getName(); // 得到文件的名称
        String parent = file.getParent(); // 得到文件的父文件夹的路径
        File parentFile = file.getParentFile(); // 得到文件的父文件夹File对象
        String path = file.getPath(); // 得到当前文件路径
    }
1.7 操作文件的操作
public static void main(String[] args) {
        File file = new File("c:\\Users\\admin\\Desktop\\aaa\\bbb\\ccc");
        /*
         * 由于文件操作会根据当前环境,而导致操作不成功
         * 所以需要手动的处理异常
         */
        try {
             // 创建一个新的文件
            // 如果路径找不到,会抛出异常,系统找不到指定的路径
            // 如果文件已经存在,可能导致创建无效(建议判断是否存在)
            boolean b = file.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 如果文件存在,则删除并返回true,如果不存在则返回false
        boolean b1 = file.delete(); // 删除一个文件,如果删除一个文件夹,需要空的文件夹才能删除
        System.out.println(b1);
        long len = file.length(); // 得到文件内容字节数
        System.out.println(len);
        // 文件夹操作
        String [] paths = file.list(); // 得到文件夹中文件名称(短名称)的列表
        for (String string : paths) {
            System.out.println(string);
        }
        File [] files = file.listFiles(); // 得到文件夹中文件的列表
        for (File file2 : files) {
            System.out.println(file2.getPath());
        }
        boolean b2 = file.mkdir(); // 创建一个文件夹
        System.out.println(b2);
        boolean b3 = file.mkdirs(); // 创建文件夹,如果路径中包含不存在文件夹,一起创建
        System.out.println(b3);
        File destFile = new File("c:\\Users\\admin\\Desktop\\aaa\\bbb\\3.txt");
        file.renameTo(destFile); // 同一个文件夹,则重命名,不同的文件夹,则移动文件
    }

测试:读取一个文件夹,将文件夹中的内容结构复制到另一个文件夹中。

public static void main(String[] args) {
        // 复制一个文件夹aaa中的结构到另一个文件夹aaaa中(包含文件夹中的文件和子文件夹里面的文件)
        /*分解步骤:
         1. 递归遍历源文件夹中的所有文件(包含子文件夹中的文件)
         2. 在递归的过程中,判断当前文件是文件夹还是文件,如果是文件夹,则创建文件夹,如果是文件,则创建文件(在目标地址创建)
         */
        String srcPath = "C:\\Users\\admin\\Desktop\\img";
        String descPath = "C:\\Users\\admin\\Desktop\\aaaa";
        File srcFile = new File(srcPath); // 创建一个源文件的目录
        File descFile = new File(descPath); // 创建一个目标文件的目录
        if(!descFile.exists()) { // 如果目标文件夹不存在
            descFile.mkdirs(); // 创建一个文件夹
        }
        if(srcFile.isDirectory()) { // 判断是否目录
            getListFile(srcFile, descFile);
        }        
    }
    /**
     * 遍历文件夹,复制内容
     * @param directory
     */
    public static void getListFile(File directory, File descFile) {
        File [] list = directory.listFiles(); // 得到当前源文件夹中的所有文件
        for (File file : list) {
            // 创建一个File对象
            File newFile = new File(descFile, file.getName());
            if(file.isFile()) { // 如果是一个文件
                try {
                    // 创建一个文件
                    newFile.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }else {
                // 创建一个文件夹
                boolean b = newFile.mkdir();
                if(b) {// 继续遍历文件夹中的内容,复制到目标文件夹中
                    getListFile(file, newFile);
                }
            }
        }
    }

2.1 流的基本概念

简单来说,流是指操作文件的通道(管道)可以称为流。

2.2 流的分类

根据流向分为输入流和输出流。 流的流向是指的内存。 读:把磁盘中的数据流向到内存中。输入 写:把内存中的数据流向到磁盘。输出

根据每次传输的字节大小分为字节流和字符流。

2.3 输入流和输出流

InputStream和OutputStream

// read()读取一个字节
    // read(buffer) 读取多个字节,
    // read(buffer, off, len) 读取多个字节,从off开始,读取len长度
    // skip 跳过多个字节,然后读取
    // available // 有效字节长度
    public static void main(String[] args) {
        readBuffer();
    }

    /**
     * 每次读取多个字节来读取文件
     */
    public static void readBuffer() {
        File file = new File("C:\\Users\\admin\\Desktop\\aaa\\a.txt");
        try {
            // 创建一个文件的输入流对象
            InputStream is = new FileInputStream(file);
//            is.skip(5); // 跳过5个字节
            int a = is.available();
            System.out.println("a=====" + a);
            // 循环终止条件,当读取到字节值为-1时
            byte [] buffer = new byte[1024];
            int i; // 当次读取有效字节长度
            while((i = is.read(buffer)) != -1) {
                System.out.print(new String(buffer, 0, i)); // 字节内容,起始位置,长度
            }
            System.out.println("====end====");
            // 关闭流
            is.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 每次读取一个字节来读取文件
     */
    public static void readByte() {
        File file = new File("C:\\Users\\admin\\Desktop\\aaa\\a.txt");
        try {
            // 创建一个文件的输入流对象
            InputStream is = new FileInputStream(file);
            // 循环终止条件,当读取到字节值为-1时
            int i;
            while((i = is.read()) != -1) {
                System.out.print((char)i);
            }
            // 关闭流
            is.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

IO流

1.1 输出流

OutputStream,作用主要是用来将内存中数据进行输出。

/**
 * 使用基础的输出流
 * @author admin
 * write(int) 写入一个ASCII码
 * write(byte []) 写入一个字节数组
 * write(byte [] bytes, int off, int len)从一个字节数组的第off位开始,写入len个字节
 * flush() 刷新,清空缓冲区,写入到目标
 * close() 关闭流,会在关闭前清空缓冲区
 */
public class MyOutputStreamDemo {
    public static void main(String[] args) {
        // 1. 将一段文字写入到文件
        String destPath = "C:\\Users\\admin\\Desktop\\aaa\\b.txt";
        File file = new File(destPath);
        try {
            // 创建一个输出流
            OutputStream os = new FileOutputStream(file, true); // 如果不写或者写false,会覆盖原来的内容,true则表示追加在后面
            os.write(51); // 写入51(ASCII码,代表数字3)
            os.write(13); // 相当于/r
            os.write(10); // 相当于/n
            String s = "Hello, world";
            byte [] bytes = s.getBytes(); // 得到字符串的字节数组
            os.write(bytes);
            os.flush(); // 直接清空缓冲区,写入磁盘
            os.close(); // 关闭流
            /*
            当输出流写入磁盘数据时,并不是直接写入磁盘,而是先写入缓冲区,再将缓冲区数据写入磁盘。
            将缓冲区数据写入磁盘时机常见有3种:
            1. 调用flush刷新缓冲区
            2. 使用close关闭流
            3. 缓冲区使用满时
             */
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
1.2 字符流

在处理数据时,以一个字符为单位进行处理。 FileReader和FileWriter

// FileReader用法:
public static void main(String[] args) {
        readChars();
    }
    /**
     * 读取一个字符
     */
    public static void readChar() {
        String srcPath = "C:\\Users\\admin\\Desktop\\aaa\\3.txt";
        try {
            // 创建一个字符输入流对象
            FileReader reader =  new FileReader(srcPath);
            int i = -1; // 定义读取的内容
            while((i = reader.read()) != -1) { // 判断内容不为-1,则循环读取
                System.out.println((char)i); // 使用char来显示内容,每次读取一个char(相当于2bytes),字节流每次读取一个byte
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * 读取多个字符
     */
    public static void readChars() {
        String srcPath = "C:\\Users\\admin\\Desktop\\aaa\\3.txt";
        try {
            // 创建一个字符输入流对象
            FileReader reader =  new FileReader(srcPath);
            char [] chars = new char[1024]; //定义一个读取内容的char的数组
            int i = -1; // 定义读取的长度
            while((i = reader.read(chars)) != -1) { // 判断长度不为-1,则循环读取
                String s = new String(chars, 0, i); // 将读取的实际内容组成一个字符串
                s = new String(s.getBytes("gbk"), "utf-8"); // 将原本的文字使用gbk的形式拆解成字节,然后以utf-8的形式重组成字符串
                System.out.println(s); // 
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

FileWriter用法:

/**
 * 字符输出流
 * @author admin
 * write(int) 将一个char型内容写入, 应该小于65536, 超出了会循环
 * write(char[])将一个char数组的内容写入
 * write(String)将一个字符串写入
 * 如果在代码中出现了中文,要将此中文写入文本,会自动根据当前类代码对应的编码格式来写入文件,并且会将文件的格式也改成此编码
 * 例如当前类java文件是gbk的编码,如果将哈哈哈写入文本,会将文本的编码格式也转换成gbk(在微软系统中对应的ANSI)
 */
public class MyFileWriterDemo {
    public static void main(String[] args) {
        String destPath = "C:\\Users\\admin\\Desktop\\aaa\\1.txt";
        try {
            FileWriter writer = new FileWriter(destPath, true); // 创建字符输出流
            writer.write(65548-65536);  // 写入一个int型数据(会转换成char)
            char [] chars = {'A', 'B', '西'}; // 写入char数组数据,注意中文的编码
            writer.write(chars);
            writer.write("哈哈哈"); // 写入字符串
            writer.flush(); 
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

1.3 转换流

一般来说,转换流是指将字节流转换字符流,以便解决编码问题。 InputStreamReader, OutputStreamWriter

/**
 * 转换流
 * @author admin
 *
 */
public class MyInputStreamReaderDemo {
    public static void main(String[] args) {
        write();
    }

    /**
     * 使用转换流写文件,并设置字符集
     */
    public static void write() {
        String destPath = "C:\\Users\\admin\\Desktop\\aaa\\1.txt";
        try {
            OutputStream os = new FileOutputStream(destPath, true);// 创建一个字节输出流
            OutputStreamWriter writer = new OutputStreamWriter(os, "utf-8"); // 创建一个转换流, 并设置字符集
            writer.write("面对疾风吧");
            writer.flush();
            writer.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 使用转换流读取文件,并设置字符集
     */
    public static void read() {
        String srcPath = "C:\\Users\\admin\\Desktop\\aaa\\1.txt";
        try {
            InputStream is = new FileInputStream(srcPath); // 创建一个字节流
            InputStreamReader reader = new InputStreamReader(is, "utf-8"); // 使用上面的字节流创建一个字符转换流,并且设置文件的编码
            char [] chars = new char[1024];
            int len = -1; // 得到有效字符长度
            // 读取文件
            while((len = reader.read(chars)) != -1) {
                String s = new String(chars, 0, len);
                System.out.println(s);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
1.4 缓冲流

带有缓冲的流。

/**
 * 缓冲流
 * @author admin
 */
public class MyBufferedDemo {
    public static void main(String[] args) {
        bufferedWriter();
    }

    /**
     * 带缓冲的字符的输出流
     */
    public static void bufferedWriter() {
        String destPath = "C:\\Users\\admin\\Desktop\\aaa\\3.txt";
        try {
            // 通过转换流设置字符集,创建一个追加内容的缓冲输出字符流
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(destPath, true), "utf-8"));
            bw.write("左手画一条龙");
            bw.newLine(); // 换行
            bw.write("右手画一道彩虹");
            bw.flush();
            bw.close();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 带缓冲的字符的输入流
     */
    public static void bufferedReader() {
        String srcPath = "C:\\Users\\admin\\Desktop\\aaa\\3.txt";
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(srcPath), "utf-8")); // 通过转换流设置字符集,创建一个缓冲流
            String str = reader.readLine(); // 读取一行
            System.out.println(str);
            reader.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 与字节输出流代码操作上一样。
     * 从原理上来说,原来的字节输出流每次写入内容,会写入到系统的缓冲区,而带缓冲的输出流每次在写入的时候,只是把内容写入到了当前流的缓冲区,当流的缓冲区满了,才会写入到系统的缓冲区
     */
    public static void bufferedOutput() {
        String destPath = "C:\\Users\\admin\\Desktop\\aaa\\a.txt";
        try {
            OutputStream os = new FileOutputStream(destPath);
            BufferedOutputStream bos = new BufferedOutputStream(os);
            bos.write(53);
            bos.flush();
            bos.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * 缓冲输入字节流由于自带缓冲,所以可以在读取的时候设置标记,并回档到标记的地方
     */
    public static void bufferedInput() {
        String srcPath = "C:\\Users\\admin\\Desktop\\aaa\\a.txt";
        try {
            InputStream is = new FileInputStream(srcPath); // 创建一个字节输入流
            BufferedInputStream bis = new BufferedInputStream(is); // 创建一个缓冲输入流

            int i = bis.read(); // 读取一个字节
            bis.mark(9); // 在当前字节设置一个临时标记,记录当前位置,实际是在buffer中记录的, mark中的参数使用当前文件能读取的最大字节数
            int j = bis.read(); // 读取一个字节
            System.out.println((char)i + "===" +(char)j);
            bis.reset(); // 回档到原来设置标记的地方开始重新读取内容
            i = bis.read();
            j = bis.read();
            System.out.println((char)i + "===" + (char)j);            
            bis.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
1.5 内存流
1.6 标准输入输出流
1.7 对象流和序列化

对象流是操作对象的流,可以将对象直接写入文件,或者在文件中读取对象。 序列化是指将对象转成有序列的流的方式,反序列化将文件内容有序的转换成对象的方式。 对于Java来说,要实现序列化的要求很简单,只需要实现java.io.Serializable接口即可,而且此接口中没有任何方法。

序列化id应该在项目中是唯一的,它的作用是保证当前项目中对象被序列化后,可以安全的反序列化,如果在反序列化时,id不一致,则会出现异常。

transient 关键字修饰属性,表示在序列化时不会将该关键字修饰的属性序列化,那么反序列化时该属性值为空。

public class Student implements java.io.Serializable{
    private static final long serialVersionUID = 6554237497611252685L;

    private int id;
    private String name;
    private transient Integer age; // 表示该属性不会被序列化

    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
}

/**
 * 对象流
 * @author admin
 * 如果使用对象流,需要对象对应的类实现序列化接口,如果没有实现,则会出现java.io.NotSerializableException: 异常
 */
public class MyObjectStreamDemo {
    public static void main(String[] args) {
//        writeObject();
        readObject();
    }

    /**
     * 将对象读入到内存
     */
    public static void readObject() {
        String srcPath = "C:\\Users\\admin\\Desktop\\aaa\\2.txt";
        try {
            // 创建一个对象读取的流
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream(srcPath));
            // 读取对象
            Student stu = (Student) ois.readObject(); // 并不能循环读取,只能读取一次, 如果有多个对象,可以存入集合再保存
            System.out.println("id:" + stu.getId() + ", name:" +stu.getName() + ",age:" + stu.getAge());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 将对象写入文件
     */
    public static void writeObject() {
        String srcPath = "C:\\Users\\admin\\Desktop\\aaa\\2.txt";
        try {
            // 创建一个对象流
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(srcPath));
            // 创建一个对象(需要实现序列化接口)
            Student stu = new Student();
            stu.setId(1);
            stu.setName("张三");
            stu.setAge(20);
            // 写入文件
            oos.writeObject(stu);
            oos.flush();
            oos.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

相关文章

网友评论

      本文标题:011-文件和流的基本用法

      本文链接:https://www.haomeiwen.com/subject/ivewehtx.html