美文网首页
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