欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

IO 【vaynexiao】

程序员文章站 2024-03-02 23:00:22
...

https://edu.51cto.com/course/17347.html 汤小洋

基础

1. 简介

IO:Input Output 输入和输出流

  • 通过IO流实现文件的输入和输出功能
  • 用于对文件进行读写的操作
    流stream:可以理解为一组有顺序的、有起点和终点的动态数据集合
  • 文件是数据在硬盘上的静态存储
  • 流是数据在传输时的动态形态

2. 文件的分类(两类)

  • 文本文件
    可以使用记事本编辑的文件, .txt .java .properties
  • 二进制文件
    除了文本文件,其他所有文件都是二进制文件

InputStream是字节输入流的顶层父类,常用子类:

  • FileInputStream
  • ByteArrayInputStream
  • ObjectInputStream
    OutputStream是字节输出流的顶层父类,常用子类:
  • FileOutputStream
  • ByteArrayOutputStream
  • ObjectOutputStream

3. 流的分类(三类)

按流的方向(站在Java程序的角度)

  • 输入流:用于读取数据,比如从文件中读取数据到程序中,由InputStream和Reader作为父类
  • 输出流:用于写出数据,比如将程序中的数据写出到文件中,由OutputStream和Writer作为父类
    按流中数据的单位
  • 字节流byte:所操作的最小数据单元为字节,由InputStream和OutputStream作为父类
  • 字符流char:所操作的最小数据单元为字符,由Reader和Writer作为父类,
    【一个英文字符占1个字节,一个汉字占2个字节(GBK) 或 3个字节(UTF8)】
    按数据的来源
  • 节点流:直接对数据源进行操作,如操作文件
  • 包装流:对一个节点流进行操作(包装)
    IO 【vaynexiao】
    IO 【vaynexiao】
    IO 【vaynexiao】

基础API

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.Date;

public class Test01 {
    public static void main(String[] args) throws URISyntaxException, IOException {
        //java.io.File

        /*
        * 创建一个File对象
        */

        // 方式1:指定文件的全路径
        // File file = new File("D:\\resource\\a.txt"); // 绝对路径
        // File file = new File("D:/resource/a.txt");
        // File file = new File("/home/soft01/a.txt");
        // File file = new File("a.txt"); //相对路径

        // 方式2:指定父目录的路径和文件名
        // File file = new File("C:/resource", "code/a.txt");

        // 方式3:指定父目录的File对象和文件名
        File file1 = new File(new File("C:/resource"), "code/a.txt");
        System.out.println("file1=:"+file1);//C:\resource\code\a.txt

        // 方式4:指定URI统一资源标识符
        File file2 = new File( Test01.class .getClassLoader() // 获取类加载器
           .getResource("data.properties") // 加载类路径下的文件(当然文件得存在),返回URL(UniformResource Locator统一资源定位符)
             .toURI() // 转换为URI(Uniform Resource Identifier统一资源标识符)
        );
        System.out.println("file2=:"+file2);//C:\idea_pro\io\target\classes\data.properties

        File file = new File("c.txt"); // 放在项目根目录下才能找到,java默认是相对于项目的根目录
        System.out.println("文件名:"+file.getName());//文件名:c.txt
        System.out.println("路径名:"+file.getPath());//路径名:c.txt
        System.out.println("绝对路径名:"+file.getAbsolutePath());//绝对路径名:C:\idea_pro\io\c.txt
        System.out.println("父目录:"+file.getParent());//null
        System.out.println("父目录文件对象:"+file.getParentFile()); //null 返回的是File对象
        System.out.println("文件长度:"+file.length()+"字节");//文件长度:10字节
        System.out.println("最后一次修改时间:"+new Date(file.lastModified()));//Sun May 10 16:59:38 CST 2020 lastModified()返回的是long值
        System.out.println("是否可读:"+file.canRead());//是否可读:true
        System.out.println("是否可写:"+file.canWrite());//是否可写:true
        System.out.println("是否为普通文件:"+file.isFile());//是否为普通文件:true
        System.out.println("是否为目录:"+file.isDirectory());//是否为目录:false
        System.out.println("是否为隐藏文件:"+file.isHidden());//是否为隐藏文件:false
        System.out.println(file); //c.txt 直接输出File对象,本质上就是调用getPath()
        System.out.println(file.exists()); //true 判断指定路径的文件是否存在

        /*
        * 文件目录的操作
        */
        File file3 = new File("C:/resource/c.txt");
        boolean isSuccess = file3.createNewFile();  // 创建一个空文件,返回一个boolean,表示成功或失败
        System.out.println("是否创建成功"+isSuccess);
        file3.renameTo(new File("c2.txt")); //重命名 这里是相对路径会在项目根目录下新建c2.txt文件
        boolean isSuccess2 = file3.delete(); //删除文件
        System.out.println("删除是否成功"+isSuccess2);

        File f = new File("D:/software");
        // boolean isSuccess = f.mkdir(); // 创建目录,如果父目录不存在 ,会导致创建失败
        // boolean isSuccess = f.mkdirs(); // 创建包括父目录的目录,即级联创建
        // System.out.println(isSuccess);
        String[] names = f.list(); // 获取目录下的所有文件和目录的名称
        System.out.println(Arrays.toString(names));
        File[] files = f.listFiles(); // 获取目录下的所有文件和目录的对象
        System.out.println(Arrays.toString(files));

        // 常量
        System.out.println(File.separator);//当前系统分隔符

    }
}

案例

递归获取指定目录下所有文件

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;

public class Test01 {
    public static void main(String[] args) throws URISyntaxException, IOException {
        File file = new File("c:/idea_pro");
        display(file);

    }
    public  static  void  display(File  file)  {
                //  判断文件是否存在
                if  (!file.exists())  {
                        return;
                }
                //  判断是否为目录
                if  (file.isDirectory())  {
                        File[]  files  =  file.listFiles();
                        for  (File  f  :  files)  {
                                if(f.isFile()){
                                        System.out.println(f.getAbsolutePath());
                                }else{
                                        display(f);
                                }
                        }
                }else{
                        System.out.println(file.getAbsolutePath());
                }
        }
}

递归删除全部空目录

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;

public class Test01 {
    public static void main(String[] args) throws URISyntaxException, IOException {
        File file = new File("d:/resource");
        remove(file);

    }
    public static void remove(File file) {
        // 判断是否为空目录
        if (file.isDirectory() && file.listFiles().length == 0) {
            file.delete();
            System.out.println("删除空目录:" + file.getAbsolutePath());
            // 删除当前目录后可能导致父目录也为空,所以需要对父目录进行处理
            remove(file.getParentFile());
        } else if (file.isDirectory()) {
            // 如果当前目录不为空目录,则获取目录下所有文件进行再处理
            File[] files = file.listFiles();
            for (File f : files) {
                remove(f); // 递归删除
            }
        }
    }
}

FileInputStream 文件字节输入流

import java.io.*;
import java.net.URISyntaxException;

public class Test01 {
    public static void main(String[] args) throws URISyntaxException, IOException {
        test01();
//        test02();
//        test03();
    }
    // 基本用法
    public static void test01(){
        FileInputStream  fis = null;//不初始化时,close方法报错,怀疑可能未初始化
        try {
            //fis = new FileInputStream("a.txt");
            fis = new FileInputStream(new File("a.txt"));// 读取项目根目录下的文件
            /*
            int data = fis.read(); //处于阻塞状态,读取一个字节返回int类型的字节值,a就是97,读取到末尾返回-1
            while(data!=-1){
                System.out.println((char)data);
                data=fis.read();
            }
            */
            int data = -1;//初始值-1
            while((data=fis.read()) != -1){
                System.out.println(data+" : "+(char)data);  // 字节流读取中文时可能会出现乱码(中文utf-8时是3个字节)
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally{
            if(fis != null){ // 需要判断是否为null,防止出现NullPointerException
                try {
                    fis.close(); // 关闭输入流:只要是打开了外部的资源(文件\数据库连接\网络连接),在使用后都需要关闭,释放资源
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            
        }
    }
    
    // 其他用法
    public static void test02(){
        // 在JDK7中,提供了一种新语法,叫做try-with-resource,能够自动关闭外部资源,不需要写finally,简化代码
        try(
                // 此处只能创建实现了AutoClosable接口的对象
                FileInputStream fis=new FileInputStream("a.txt");
        ){
            //System.out.println((char)fis.read());
            //System.out.println(fis.available()); // 流中可读取的字节数
            
            byte[] buffer=new byte[1024*1024]; // 减少对硬盘的读取次数,提高效率
//          int num = fis.read(buffer); // 一次性读取buffer.length个字节到buffer中,返回实际读取到的字节数,如果读取到末尾,则返回-1
//          System.out.println(num);
//          String str = new String(buffer);
//          System.out.println(str);
//          
//          num = fis.read(buffer);
//          System.out.println(num);
            //System.out.println(new String(buffer, 0, num));  // 将指定长度的字节数组转换为字符串
            
            int num=-1;
            while((num=fis.read(buffer)) != -1){
                System.out.println(new String(buffer,0,num));
            }
        }catch(IOException e){
            e.printStackTrace();
        }
    }
    // 加载不同路径下的文件
            public static void test03(){
        try(
                // 默认加载项目根路径下
                //InputStream is=new FileInputStream("a.txt");

                // 加载classpath类路径,即src目录
                //InputStream is=Test01_FileInputStream.class.getClassLoader().getResourceAsStream("b.txt");

                // 加载当前类所在目录
                InputStream is=Test01.class.getResourceAsStream("c.txt");
        ){
            System.out.println((char)is.read());
            System.out.println("加载文件成功!");
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

FileOutputStream 文件字节输入流

IO 【vaynexiao】

import java.io.*;

public class Test01 {
    public static void main(String[] args) {
        FileOutputStream fos = null;
        try {
            // 如果文件不存在,会自动创建文件,如果文件存在,默认会覆盖原文件的内容
            // fos=new FileOutputStream("a.txt");
            fos = new FileOutputStream("a.txt", true); // true表示以追加的形式写数据
            byte[] data = "hello world".getBytes();
            fos.write(data); // 写入数据,只是将数据写入到内存的缓冲区中,并没有真正写入到文件中
            fos.flush(); // 刷新输出流,完成数据的输出,当关闭流时会自动调用该方法
            System.out.println("写入数据成功");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

单个文件复制

import java.io.*;

public class Test01 {
    public static void main(String[] args) {
        // 如果文件不存在,会自动创建文件,如果文件存在,默认会覆盖原文件的内容
//        test01();
        test02();
    }
    /*
     * 每次复制一个字节 read()方法默认读取一个字节
     */
    public static void test01(){
        InputStream is = null;
        OutputStream  os = null;
        
        try {
            is = new FileInputStream("a.txt");
            os = new FileOutputStream("aa.txt");
            
            int data=-1;
            while((data=is.read())!=-1){
                os.write(data); // 读一个字节,写一个字节
            }
            System.out.println("文件复制成功");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            if(os!=null){
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(is!=null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    /*
     * 每次复制多个字节 read(arg)方法默认读取指定参数个字节
     */
    public static void test02(){
        try(
            InputStream is = new FileInputStream("C:\\software\\oss-browser-win32-x64\\oss-browser.exe");
            OutputStream os = new FileOutputStream("oss.exe");
        ){
            byte[] buffer = new byte[1024*1024];
            int num = -1;
            while((num=is.read(buffer)) != -1){
                os.write(buffer, 0, num);
            }
            System.out.println("文件复制成功");
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

复制目录下所有文件到目标目录

import java.io.*;

public class Test01 {
    public static void main(String[] args) {
        copyFile("C:/software","c:/backup");
    }
    public static void copyFile(String srcPath, String destPath) {
        File srcFile = new File(srcPath);
        File destFile = new File(destPath);
        
        if(srcFile.isDirectory()){
            destFile=new File(destPath+File.separator+srcFile.getName());
            destFile.mkdirs();
            
            File[] files = srcFile.listFiles();
            for (File file : files) {
                copyFile(file.getAbsolutePath(), destFile.getAbsolutePath());
            }
        }else if(srcFile.isFile()){
            try(
                InputStream is=new FileInputStream(srcFile);
                OutputStream os=new FileOutputStream(destPath+File.separator+srcFile.getName());
            ){
                byte[] buffer=new byte[1024*1024];
                int num=-1;
                while((num=is.read(buffer))!=-1){
                    os.write(buffer, 0, num);
                }
                System.out.println("复制"+srcPath);
            }catch(IOException e){
                e.printStackTrace();
            }
        }
    }
}

字节数组输入输出流

import java.io.*;

public class Test01 {
    public static void main(String[] args) {
//    流(数据)的来源或目的地并不一定是文件,也可以是内存中的一块空间,例如一个字节数组
//    ByteArrayInputStream 字节数组输入流:从字节数组中读取数据,即将字节数组当作流输入的来源
//    ByteArrayOutputStream 字节数组输出流:将数据写出到内置的字节数组中,即将字节数组当作流输出的目的地
        test01();
        test02();
    }
    // ByteArrayInputStream
    public static void test01(){
        byte[] data="welcome to java".getBytes();
        try {
            // 定义字节数组输入流,数据来源为字节数组
            InputStream is = new ByteArrayInputStream(data);
            
            int i=-1;
            while((i=is.read())!=-1){
                System.out.print((char)i);
            }
            //输出welcome to java
        } catch (IOException e) {
            e.printStackTrace();
        }
        /*
         * ByteArrayInputStream和ByteArrayOutputStream不需要关闭
         * 因为其操作的是内存中的字节数组,属于内存读写流,并非操作的外部资源
         */
    }
    // ByteArrayOutputStream
            public static void test02(){
        try {
            ByteArrayOutputStream os = new ByteArrayOutputStream(); 
            // 将数据写出到内置的字节数组中
            os.write("hello".getBytes());
            os.flush();
            // 获取内置的字节数组中的数据
            byte[] buffer = os.toByteArray();
            System.out.println(new String(buffer));//hello
            System.out.println(os.toString());//hello
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

对象输入输出流

如果希望将Java对象写入到IO流中,或从IO流中读取Java对象,则要使用对象输入输出流,称为对象的序列化和反序列化

4.1 序列化和反序列化
序列化:将Java对象写入IO流中,实现将对象保存在磁盘上或在网络中传递对象
反序列化:从IO流中读取Java对象,实现从磁盘上或网络中恢复对象
    要求:
    对象必须实现Serializable接口,才能被序列化,转换为二进制流,通过网络进行传输
    通过 serialVersionUID 判断对象的序列化版本的一致性:
        在反序列时,会将流中的serialVersionUID与本地相应实体对象/类的serialVersionUID进行比较
            如果相同就认为版本一致,则可以进行反序列化
            如果不相同,则会出现序列化版本不一致的异常InvalidClassException

4.2 ObjectInputStream
对象输入流:用来读取对象,即反序列化
ObjectInputStream 和 ObjectOutputStream 属于包装流(用于对节点流进行功能扩展 / 包装)
在创建包装流,需要传入要操作的节点流对象
当关闭流时,只需要关闭包装流,被包装的节点流也会被关闭

4.3 ObjectOutputStream
对象输出流:用来写入对象,即序列化

User.java

import java.io.Serializable;

public class User implements Serializable {
    // static final long serialVersionUID
    // 根据类名、接口名、成员方法和属性等生成的一个64位的哈希值
    // 表示对象类型的的唯一标识
    private static final long serialVersionUID = 705661196096434175L;
    private Integer id; // 都使用包装类型,默认为null
    private String name;
    private transient Integer age;  // transient修饰的属性不会被序列化(static变量也不会被序列化)
    private Address address; // 对象属性也必须实现Serializable接口
    public User(Integer id, String name, Integer age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer 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;
    }
    public Address getAddress() {
        return address;
    }
    public void setAddress(Address address) {
        this.address = address;
    }
}

Address.java

import java.io.Serializable;

public class Address implements Serializable {
    private String province;
    private String city;
    public Address() {
        super();
    }
    public Address(String province, String city) {
        super();
        this.province = province;
        this.city = city;
    }
    public String getProvince() {
        return province;
    }
    public void setProvince(String province) {
        this.province = province;
    }
    public String getCity() {
        return city;
    }
    public void setCity(String city) {
        this.city = city;
    }
    @Override
    public String toString() {
        return "Address [province=" + province + ", city=" + city + "]";
    }
}

Test.java

import java.io.*;
import java.util.Arrays;
import java.util.List;

public class Test01 {
    public static void main(String[] args) {
        test01();
        test02();
    }
    // 序列化,写入对象
    public static void test01() {
        User u1 = new User(1001, "tom", 18);
        u1.setAddress(new Address("江苏", "南京"));

        User u2 = new User(1002, "jack", 21);
        u1.setAddress(new Address("江苏", "扬州"));

        List<User> users = Arrays.asList(u1, u2);
        ObjectOutputStream oos = null;
        try {
            // FileOutputStream fos = new FileOutputStream("user.data");
            // oos = new ObjectOutputStream(fos);
            //输出到user.data文件中,是二进制文件,文本编辑器打开不能正常显示
            oos = new ObjectOutputStream(new FileOutputStream("user.data"));
            
            // 写入对象
            // oos.writeObject(u1);
            // oos.writeObject(u2);
            oos.writeObject(users);
            oos.flush();//这里不flush也行,后面有close
            System.out.println("写入对象成功");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (oos != null) {
                try {
                    oos.close(); // 只需要关闭包装流
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    // 反序列化,读取对象
    public static void test02() {
        ObjectInputStream ois = null;
        try {
            ois = new ObjectInputStream(new FileInputStream("user.data"));
            // 读取顺序和写入顺序一致
            // User u1 = (User) ois.readObject();
            // User u2 = (User) ois.readObject();
            // System.out.println(u1);
            // System.out.println(u2);
            List<User> list = (List<User>) ois.readObject();
            System.out.println(list);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (ois != null) {
                try {
                    ois.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

文件的拆分和合并

import java.io.*;

public class Test01 {
    public static void main(String[] args) {
        // 路径不包含bak的话报错,不知为何,总之不能在根目录下操作
        splitFile("C:\\bak\\oss.zip");
        mergeFile("C:\\bak\\oss.zip_1");
    }
    // 拆分文件:一个输入流,多个输出流
    public static void splitFile(String filePath) {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            fis = new FileInputStream(filePath);
            byte[] buffer = new byte[1024 * 1024 * 10]; // 每次读取10M
            int num = -1;
            int index = 0;
            while ((num = fis.read(buffer)) != -1) {
                fos = new FileOutputStream(filePath + "_" + (++index));
                fos.write(buffer, 0, num);
                fos.flush();
                fos.close();
            }
            System.out.println("拆分成功,共拆分为:" + index + "个");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    // 合并文件:一个输出流,多个输入流
    public static void mergeFile(String filePath) { //filePath只需要一个文件名,通过截取即可
        String basePath = filePath.substring(0, filePath.lastIndexOf("_"));
        FileOutputStream fos = null;
        FileInputStream fis = null;
        try {
            fos = new FileOutputStream(basePath);
            int index = 1;
            File f = null;
            while ((f = new File(basePath + "_" + index++)).exists()) {
                fis = new FileInputStream(f);
                byte[] buffer = new byte[fis.available()];
                fis.read(buffer);
                fos.write(buffer);
                fos.flush();
                fis.close();
            }
            System.out.println("合并成功:"+basePath);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

文件字符流

import java.io.*;

public class Test01 {
    public static void main(String[] args) {
        /*
        * FileReader、FileWriter的用法与FileInputStream、FileOutputStream类似
        * 前者是以字符为单位,后者是以字节为单位
        */
        try(
            Reader reader=new FileReader("User.java"); // 字符流无法读写二进制文件,
            Writer writer = new FileWriter("User2.java")
        ){
            //int data = reader.read(); // 每次读取一个字符,返回int类型的字符值
            //System.out.println((char)data);
            
            char[] buffer=new char[5];
            int num = -1;
            while((num=reader.read(buffer))!=-1){
                writer.write(buffer, 0, num);
            }
            System.out.println("复制文件成功");
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

字符缓冲输入输出流 打印流

包装流 BufferedReader PrintWriter

import java.io.*;

public class Test01 {
    public static void main(String[] args) {
        try(
            BufferedReader reader = new BufferedReader( new FileReader("a.txt") );
            //BufferedWriter writer = new BufferedWriter(new FileWriter("aaaa.txt"));
            PrintWriter writer = new PrintWriter("aaaa.txt");   
        ){
            //String data = reader.readLine(); // 每次读取一次,读不到数据时返回null
            //System.out.println(data);
            String data = null;
            while((data = reader.readLine()) != null){
                //writer.write(data);
                //writer.newLine(); //插入换行符
                //writer.write("\r\n"); // 也可以插入\r\n进行换行
                writer.println(data); // 写入并换行,更方便
            }
            System.out.println("复制文件成功");
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

转换流

  • 用于将字节流转换为字符流,同时可以实现编码的转换
  • 在转换时需要指定使用的字符集,如果不指定默认使用JVM的字符集
  • 在Java中没有提供将字符流转换为字节流的方法,不支持该操作

InputStreamReader
将字节输入流转换为字符输入流(InputStream - Reader)
OutputStreamWriter
将字节输出流转换字符输出流(OutputStream - Writer)

public class Test03_转换流 {
    public static void main(String[] args) {
        try(
//          FileInputStream fis = new FileInputStream("a.txt");
//          InputStreamReader isr = new InputStreamReader(fis, "gbk");
//          BufferedReader reader=new BufferedReader(isr);  
            
            BufferedReader reader=new BufferedReader(
                    new InputStreamReader( new FileInputStream("b.txt") ,"gbk") // 以gbk编码读取文件
            );  
                
            // BufferedReader reader = new BufferedReader(new InputStreamReader
            // (Test03_转换流.class.getClassLoader().getResourceAsStream("b.txt")));
                
//          BufferedWriter writer=new BufferedWriter(
//                  new OutputStreamWriter(
//                          new FileOutputStream("c.txt")
//                  ,"utf-8")  // 以utf-8编码写入文件
//          );  
            PrintWriter writer = new PrintWriter("c.txt", "utf-8"); // 这个最强大
        ){
//          System.out.println(reader.readLine());
            writer.write(reader.readLine());
            System.out.println("复制文件成功");
        }catch(IOException e){
            e.printStackTrace();
            
        }
    }
}

RandomAccessFile

随机读写流,是一个字节流,可以对文件进行随机读写

  • 随机:可以定位到文件的任意位置进行读写操作,通过移动指针(Pointer)来实现
  • 读写:使用该流既能读取文件,也能写入文件
public class Test {
    public static void main(String[] args) {
        try(
            /*
             * 当文件不存在时:
             *      如果模式为r,会报异常FileNotFoundException
             *      如果模式为rw,会自动创建文件
             */
            RandomAccessFile raf=new RandomAccessFile("x.txt", "rw"); //模式:r只读、rw读写
        ){
            System.out.println(raf.getFilePointer()); // 获取当前指针的位置,从0开始
            
            raf.write("张三".getBytes()); //对于utf-8,一个汉字占3个字节
            raf.write("hello".getBytes());
            System.out.println(raf.getFilePointer()); // 11
            
            System.out.println("写入成功");
            
            raf.seek(8); // 将指针移动到指定的位置
            raf.write("李四".getBytes());
            System.out.println(raf.getFilePointer()); // 14
            
            raf.seek(6);
            byte[] buffer = new byte[2];
            raf.read(buffer);
            System.out.println(new String(buffer));
            System.out.println(raf.getFilePointer()); // 8
            
            raf.skipBytes(3); // 将指针向后跳过指定的字节,只能往前,不能倒退 ——>
            buffer = new byte[1024*1024];
            int num = -1;
            while((num = raf.read(buffer)) != -1){
                System.out.println(new String(buffer,0,num));
            }
            
            // 修改数据
            raf.seek(8);
            raf.write("赵".getBytes());
            System.out.println("修改成功");
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

文件的加密

* 实现文件的加密
 *  a.txt ——> a.txt.sec
 * 
 * 思路:读取文件中的每个字节,与pwd进行异或的操作
 */

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

public class Test01 {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        System.out.print("请输入文件路径:");
        String filePath=input.nextLine();
        System.out.print("请输入密码:");
        int pwd = input.nextInt();
        secret(filePath, pwd);
        System.out.println("加密成功");
    }
    public static void secret(String filePath, int pwd){
        try(
            FileInputStream fis=new FileInputStream(filePath);
            FileOutputStream fos = new FileOutputStream(filePath+".sec");
        ){
            int data=-1;
            while((data=fis.read())!=-1){
                fos.write(data ^ pwd);
            }
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}
相关标签: JavaEE