Java-IO流看这一篇就够了

目录

IO流分类

字节输出流

idea中文件的相对路径

使用byte[]数组写入

续写和换行

字节输入流

文件拷贝

异常捕获

字符集

编码和解码

字符流 

综合练习

使用字节流拷贝文件夹

使用异或为文件加密

缓冲流

综合练习

转换流

序列化流

 ​编辑

打印流

解压缩流/压缩流

 Commons-io

 hutool工具包


IO流分类

字节流:可以操作任何文件

字符流:只能操作文本文件(记事本可以直接打开的文件)

字节输出流

快速入门:使用字节流向文件写入数据

//使用字节输出流
@Test
public void test1() throws Exception {
    FileOutputStream fileOutputStream = new FileOutputStream("a.txt");
    fileOutputStream.write(97);
    fileOutputStream.close();
}

idea中文件的相对路径

细节:

创建输出对象的时候:1.可以是字符串或者new File 2.文件不存在时会自动创建但是父文件必须存 

在 3.文件已经存在则必须被清空

写数据:参数虽然是整数,但是写入文件的是ascii码所对应的字符

关闭流:每次都要关闭流,要不然会一直占用该文件

使用byte[]数组写入

/**
 * fileOutputStream.write(byte[], off, len) 
 * off:开始索引 len:长度
 * 当只有byte[]的时候则会将数组全部写入文件
 */
byte[] bytes = new byte[]{97, 98, 99, 77, 16};
fileOutputStream.write(bytes, 1, 2);
fileOutputStream.close();

续写和换行

换行:在windows中换行符为"\n",将其转为byte[]后写入文件中

续写:在写入文件的时候加上参数True

FileOutputStream fileOutputStream = new FileOutputStream("a.txt", true);


String s = "kangelaoyezuisuai";
byte[] bytes = s.getBytes();
fileOutputStream.write(bytes, 1, 2);

//使用换行符换行
String ss = "\n";
byte[] bytes1 = ss.getBytes();
fileOutputStream.write(bytes1);
//再次写入
fileOutputStream.write(bytes, 1, 2);

fileOutputStream.close();

字节输入流

read会向文件中一个一个的读取,当读取不到的时候返回-1

FileInputStream fis = new FileInputStream("a.txt");
    int read = fis.read();
    System.out.println((char)read);
    read = fis.read();
    System.out.println((char)read);
    read = fis.read();
    System.out.println((char)read);
    read = fis.read();
    System.out.println((char)read);
    read = fis.read();
    System.out.println((char)read);
    read = fis.read();
    System.out.println((char)read);
    //如果读取结束会返回-1
    int i = fis.read();
    System.out.println(i);
    fis.close();

细节:1.如果文件不存在则会直接报错 2.程序读取的是数据在ascii上对应的数字

字节流的循环读取

FileInputStream fis = new FileInputStream("a.txt");
    //字节输入流的循环读取
    int b;
    while((b = fis.read()) != -1){
        System.out.print((char)b);
    }
    fis.close();

文件拷贝

//文件拷贝
    FileInputStream fileInputStream = new FileInputStream("a.txt");
    FileOutputStream fileOutputStream = new FileOutputStream("b.txt");
    int b;
    while((b = fileInputStream.read()) != -1){
        fileOutputStream.write(b);
    }
    fileOutputStream.close();
    fileInputStream.close();

 使用fileInputStream对象的read方法读取byte[]数组,返回值len表示读取到了几个

我们在a.txt文件中写入abcdefa使用byte[]进行读取

//使用bytes[]数组对文件进行读取,返回值为读取的个数
FileInputStream fileInputStream = new FileInputStream("a.txt");
byte[] b = new byte[2];//表示一次读取两个字节
int read = fileInputStream.read(b);
System.out.println(new String(b) + " " + read);
read = fileInputStream.read(b);
System.out.println(new String(b) + " " + read);
read = fileInputStream.read(b);
System.out.println(new String(b) + " " + read);
read = fileInputStream.read(b);
System.out.println(new String(b) + " " + read);
fileInputStream.close();

结果如下:

最后结果返回af和值1,这是因为在byte[]数组中每次都是覆盖操作,最后只读到了1个字节,并被返回,在byte[]中也只会覆盖一个后面还是原来旧数据 

我们使用byte[]对文件拷贝进行改进

//使用byte[]数组的文件拷贝
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\lenovo\\Desktop\\e824fa78757ba86b7d6049ed60d90c2.jpg");
FileOutputStream fileOutputStream = new FileOutputStream("i.jpg");
int len;
byte[] b = new byte[1024 * 1024 * 5];
while((len = fileInputStream.read(b)) != -1){
    fileOutputStream.write(b, 0, len);
}
//先打开的后关闭
fileOutputStream.close();
fileInputStream.close();

异常捕获

因为IO流的关闭在最后必须被操作,所以我们将他们移到finally中;通道也可能未被创建,所以我们在关闭之前需要判断是否为空

idea中一般的写法

    FileInputStream fileInputStream = null;
    FileOutputStream fileOutputStream = null;

    try {
        fileInputStream = new FileInputStream("C:\\Users\\lenovo\\Desktop\\e824fa78757ba86b7d6049ed60d90c2.jpg");
        fileOutputStream = new FileOutputStream("i.jpg");
        int len;
        byte[] b = new byte[1024 * 1024 * 5];
        while ((len = fileInputStream.read(b)) != -1) {
            fileOutputStream.write(b, 0, len);
        }
    } catch (IOException e) {
        throw new RuntimeException(e);
    } finally {
        //先打开的后关闭
        if (fileOutputStream != null) fileOutputStream.close();
        if (fileInputStream != null) fileInputStream.close();
    }

实现AutoCloseAble的对象可以将流放在try中可以实现自动关闭,写法如下

    FileInputStream fileInputStream = new FileInputStream("C:\\Users\\lenovo\\Desktop\\e824fa78757ba86b7d6049ed60d90c2.jpg");
    FileOutputStream fileOutputStream = new FileOutputStream("i.jpg");
    try (fileOutputStream; fileInputStream) {
        int len;
        byte[] b = new byte[1024 * 1024 * 5];
        while ((len = fileInputStream.read(b)) != -1) {
            fileOutputStream.write(b, 0, len);
        }
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
    }

字符集

GBK

汉字:在计算机中以两个字节存储,并以1开始

英文:在计算机中以一个字节存储,并以0开始

编码:将数字转为计算机内存储的  解码:将计算机存储的转为对应的数字

unicode

英文:一个字节 0XXXXXXX

中文:三个字节 1110XXXX 10XXXXXX 10XXXXXX

编码和解码

    //编码
    String s = "ai爱你哟";
    byte[] bytes = s.getBytes();//在idea中默认使用UTF-8进行编码
    byte[] bytes1 = s.getBytes("GBK");//在ecplise中默认使用GBK进行编码
    System.out.println("UFT-8: " + Arrays.toString(bytes));
    System.out.println("GBK: " + Arrays.toString(bytes1));
    /*UFT-8: [97, 105, -25, -120, -79, -28, -67, -96, -27, -109, -97]
    GBK: [97, 105, -80, -82, -60, -29, -45, -76]*/
    

    //解码
    String s1 = new String(bytes);//idea中默认也是UTF-8解码
    String s2 = new String(bytes, "GBK");
    System.out.println("UTF-8: " + s1);
    System.out.println("UTF-8: " + s2);//编码方式和解码方式不同的时候出现乱码
    /*UTF-8: ai爱你哟
    UTF-8: ai鐖变綘鍝�*/

字符流 

FileRead读取数据

/**
 * 细节:
 * read()1.在读取的时候仍是按字节读取,英文一次读一个字节,中文一次读三个字节
 *       2.在读取解码后,自动会转为十进制,我们使用char进行强转
 *       3.使用char[]进行读取数据,相当于直接用read()读取和强转
 */
FileReader fileReader = new FileReader("a.txt");
int read;
while((read = fileReader.read()) != -1){
    System.out.print((char)read);
}
fileReader.close();

/*里面的各个人说话真好听
  都是人才*/

 使用char[]数组进行读取

FileReader fileReader = new FileReader("a.txt");
int read;
//使用char[]读取
fileReader = new FileReader("a.txt");
char[] c = new char[2];
while((read = fileReader.read(c)) != -1){
    System.out.println(new String(c));
}
fileReader.close();

/**
 * 里面
 * 的各
 * 个人
 * 说话
 * 真好
 * 听
 *
 * 都是
 * 人才
 */

使用字符流输出文件

    /**
     * 使用字符流写出数据
     * void write(int c) 
     * void write(char[] c, int offend, int length)
     * void write(String str, int offend, int length)
     */
    FileWriter fileOutputStream = new FileWriter("b.txt",true);//续写
    fileOutputStream.write(25105);//根据字符集的编码方式进行编码,把编码之后的数据写到文件中去
//    fileOutputStream.close();

    /**
     * 输出结果:我
     */
    fileOutputStream.write(new char[]{'a','b','c','d','我'});
//    fileOutputStream.close();
    /**
     * 输出结果:abcd我
     */
    fileOutputStream.write("你好呀");
    /**
     * 输出结果:你好呀
     */
    fileOutputStream.close();

字符输出流缓冲区写出数据的条件:

1.缓冲区已满 2.使用flush() 3.使用close()

综合练习

使用字节流拷贝文件夹


//拷贝文件夹
File src = new File("D:\\src\\test1");
File desc = new File("D:\\src\\test2");
copydir(src, desc);


}
void copydir(File src, File desc) throws IOException {
    desc.mkdir();
    File[] files = src.listFiles();
    for (File file : files) {
        if(file.isFile()){
            FileInputStream fileInputStream = new FileInputStream(file);
            FileOutputStream fileOutputStream = new FileOutputStream(new File(desc, file.getName()));
            byte[] b = new byte[1024];
            int len = 1;
            while((len = fileInputStream.read(b)) != -1){
                fileOutputStream.write(b);
            }
            fileOutputStream.close();
            fileInputStream.close();
        }else{
            copydir(file, new File(desc, file.getName()));
        }
    }
}

使用异或为文件加密

    //文件的加密和解密,文件通过两次异或就可以恢复到原来
    FileInputStream fileInputStream = new FileInputStream("2.jpg");
    FileOutputStream fileOutputStream = new FileOutputStream("3.jpg");
    int b;
    while((b = fileInputStream.read()) != -1){
        fileOutputStream.write(b ^ 100);
    }
    fileOutputStream.close();
    fileInputStream.close();

缓冲流

 缓冲流是对基本数据流的包装,初始化时其第一个参数是基本流、第二个参数是初始化缓冲区大小,使用缓冲流可以直接关闭基本数据流

    BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt"));
    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b.txt"));
    int b;
    while((b = bis.read()) != -1){
        bos.write(b);
    }
    bis.close();
    bos.close();

可以字节流一样,我们可以使用byte[]一次多个数据

字符缓冲流特有的两个方法:1.readline()一次读取一行,并自动删除换行符 2.newLine()自动换行

    BufferedReader bufferedReader = new BufferedReader(new FileReader("a.txt"));
    String s;
    while((s = bufferedReader.readLine()) != null){
        //readline会直接读取为String
        System.out.println(s);
    }
    bufferedReader.close();

    /**
     * 输出结果:
     * d-c-b-a
     * adfsdf
     * adfdf
     */

    BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("a.txt"));
    String s1 = "nihaoa";
    bufferedWriter.write(s1);
    bufferedWriter.newLine();
    String s2 = "safkjkfa";
    bufferedWriter.write(s2);
    bufferedWriter.newLine();//使用newLine换行
    bufferedWriter.close();

综合练习

恢复文本文件中的顺序

    BufferedReader fis = new BufferedReader(new FileReader("a.txt"));
    String s;
    Map<Integer, String> map = new TreeMap<>(new Comparator<Integer>() {//使用TreeMap对元素进行排序
        @Override
        public int compare(Integer o1, Integer o2) {
            return Integer.valueOf(o1) - Integer.valueOf(o2);
        }
    });
    while((s = fis.readLine()) != null){
        map.put(Integer.parseInt(s.substring(0,1)), s);
    }
    fis.close();
    //重新写入文件
    BufferedWriter bos = new BufferedWriter(new FileWriter("a.txt"));
    map.entrySet().stream().forEach(p -> {
        try {
            bos.write(p.getValue());
            bos.newLine();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    });
    bos.close();

/*输出1.a
      2.e
      3.b
      4.d*/

 IO流原则:什么时候用什么时候打开,我们同时输出输入同一个文件会得到空

转换流

我们利用JDK11中的新特征实现转换流,FileRead/FileWriter

//1.较老的写法
InputStreamReader fis = new InputStreamReader(new FileInputStream("c.txt"), "GBK");//按GBK文件形式读取
int c;
while ((c = fis.read()) != -1) {
    System.out.print((char) c);
}
fis.close();

//2.jdk11以后推荐使用这种方式:使用FileReader直接读取
FileReader fileReader = new FileReader("c.txt", Charset.forName("GBK"));
while ((c = fileReader.read()) != -1) {
    System.out.print((char) c);
}
fileReader.close();

/**
* 输出结果:你好啊你好啊
*/

//使用转换流实现向文件输出数据
FileWriter fileWriter = new FileWriter("c.txt", Charset.forName("GBK"));
fileWriter.write("你好啊!!!!");
fileWriter.close();

使用转换流实现读取GBK文件后将文件以UTF-8的形式输出

//使用转换流实现读取GBK文件后将文件以UTF-8的形式输出
FileReader fileReader1 = new FileReader("c.txt", Charset.forName("GBK"));//以GBK形式读入
char[] c = new char[2];
int read = fileReader1.read(c);
fileReader1.close();
FileWriter fileWriter = new FileWriter("c.txt");
fileWriter.write(new String(c));//以默认utf-8形式写出
fileWriter.close();

练习:使用字节流读取文件中的数据,每次读取一行,不能出现乱码

//练习:使用字节流读取文件中的数据,每次读取一行,不能出现乱码
FileInputStream fileInputStream = new FileInputStream("c.txt");//读取为字节流
InputStreamReader gBk = new InputStreamReader(fileInputStream, "UTF-8");//为了不出现乱码,我们需要使用装换流转为字符流
BufferedReader bufferedReader = new BufferedReader(gBk);//将字符流转为缓冲流实现整行读取
String s = bufferedReader.readLine();
System.out.println(s);
bufferedReader.close();

序列化流

 

将对象写入文件中:对象需要实现Serializable标记接口

ObjectOutPutStream(OutPutStream out)将基本数据流包装为序列化流

writeObject(Object object)将对象写入文件

public class test1 {
    @Test
    public void test1() throws Exception {
        ObjectOutputStream stream = new ObjectOutputStream(new FileOutputStream("c.txt"));
        Person chen = new Person("chen", 22);
        stream.writeObject(chen);
        stream.close();
    }
}
class Person implements Serializable {
    String name;
    int age;
    Person(String name, int age){
        this.name = name;
        this.age = age;
    }
}

反序列化流和上面相似

//生成对象流
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("c.txt"));
//从对象流中获取对象
Object o = objectInputStream.readObject();
System.out.println(o);
objectInputStream.close();

我们在序列化对象的时候除了Serializable标记接口,还要添加版本号,这样我们需要修改类后就不会报错了

private static final long serialVersionUID = 8683451231122892189L;

不需要的属性我们使用transient进行标注 

transient String sex;//取消序列化

完整代码如下

public class test1 {
    //读取序列化流
    @Test
    public void test1() throws Exception {
    //生成对象流
    ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("c.txt"));
    //从对象流中获取对象
    Object o = objectInputStream.readObject();
    System.out.println(o);
    objectInputStream.close();

        /**
         * 输出结果:
         * Person{name='小明', age=12, sex='null'}
         */
    }
    //写入序列化流
    @Test
    public void test2() throws IOException {
        ObjectOutputStream stream = new ObjectOutputStream(new FileOutputStream("c.txt"));
        Person p = new Person("小明", 12, "男");
        stream.writeObject(p);
        stream.close();
    }
}
class Person implements Serializable {
    private static final long serialVersionUID = 3933706312317968362L;//全局唯一版本号
    String name;
    int age;
    transient String sex;//取消序列化

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

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                '}';
    }
}

综合练习:将多个对象写入文件,但是我们在读的时候怎么解决都多少个的问题呢,这个时候我们就可以使用ArrayList实现了

public class test1 {
    //读取序列化流
    @Test
    public void test1() throws Exception {
    //生成对象流
    ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("c.txt"));
    //从对象流中获取对象
    Object o = objectInputStream.readObject();
    ArrayList<Person> list = (ArrayList<Person>)o;//将对象强转
    for(Person p: list){
        System.out.println(p);
    }
    objectInputStream.close();

        /**
         * 输出结果:
         * Person{name='小明', age=12, sex='null'}
         */
    }
    //写入序列化流
    @Test
    public void test2() throws IOException {
        ObjectOutputStream stream = new ObjectOutputStream(new FileOutputStream("c.txt"));
        Person p1 = new Person("小明", 12, "男");
        Person p2 = new Person("小红", 12, "男");
        Person p3 = new Person("小绿", 12, "男");
        List<Person> list = new ArrayList<>();
        list.add(p1);
        list.add(p2);
        list.add(p3);
        stream.writeObject(list);//我们直接将ArrayList写入文件中
        stream.close();
    }
}
class Person implements Serializable {
    private static final long serialVersionUID = 3933706312317968362L;//全局唯一版本号
    String name;
    int age;
    transient String sex;//取消序列化

    public Person(String name, int age, String sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                '}';
    }
}

打印流

字节打印流PrintStream/字符打印流PrintWriter 打印流的特点:

  使用字节输出流printStream

    PrintStream printStream = new PrintStream(new FileOutputStream("a.txt"), true, Charset.forName("UTF-8"));
    printStream.println(97);//直接写+刷新+自动换行
    printStream.print(true);//直接写
    printStream.println();
    printStream.printf("%s 爱 %s", "小明", "小红");
    printStream.close();
    /**
     * 输出结果:
     * 97
     * true
     * 小明 爱 小红
     */

字符打印流

字符打印流方法和字节打印流方法基本相同 

//使用字符打印流要打开自动刷新
PrintWriter printWriter = new PrintWriter(new FileWriter("a.txt"), true);
printWriter.println("随便一句话");
printWriter.print("害");
printWriter.printf("%s 爱上 %s","a珍","a强");
printWriter.close();

解压缩流/压缩流

压缩包里每一个文件都是ZipEntry,解压缩的本质都是将压缩包内的文件解压缩到本地文件夹

使用解压缩流实现文件夹的解压缩

public void copy(File src, File desc) throws IOException {
    ZipInputStream zip = new ZipInputStream(new FileInputStream(src));
    ZipEntry zipEntry;
    while((zipEntry = zip.getNextEntry()) != null){//为空则说明已经遍历完了
        //如果是文件夹的话
        if(zipEntry.isDirectory()){
            File file = new File(desc, zipEntry.toString());
            file.mkdir();//直接创建文件夹
        }else{
            //如果不是文件夹直接拷贝文件
            FileOutputStream fileOutputStream = new FileOutputStream(new File(desc, zipEntry.toString()));
            int c;//一个一个字节的拷贝
            while((c = zip.read()) != -1){
                fileOutputStream.write(c);
            }
            fileOutputStream.close();
            //表示压缩包内的一个文件处理完了
            zip.closeEntry();
        }
    }
    zip.close();
}

压缩文件夹

//压缩文件夹
    @Test
    public void test7() throws IOException {
        //要拷贝的文件
        File file = new File("D:\\src\\test4");

        ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(new File(file.getParent(), file.getName() + ".zip")));
        //注意这里要多加一个参数,否则后面文件不好命名
        fileToZip(file, zipOutputStream, file.getName());
        zipOutputStream.close();
    }
    void fileToZip(File src, ZipOutputStream desc, String name) throws IOException {
        File[] files = src.listFiles();
        for(File file: files){
            if(file.isFile()){//如果是文件的话
                ZipEntry zipEntry = new ZipEntry(new File(name, file.getName()).toString());
                desc.putNextEntry(zipEntry);
                int b = 0;
                FileInputStream fileInputStream = new FileInputStream(file);
                while((b = fileInputStream.read()) != -1){
                    desc.write(b);
                }
                desc.closeEntry();
                fileInputStream.close();
            }else {//如果是文件夹的话
                fileToZip(file, desc, name + "//" + file.getName());
            }
        }
    }

 Commons-io

        /*//拷贝文件
        File src = new File("a.txt");
        File desc = new File("copy.txt");
        FileUtils.copyFile(src,desc);*/

        //复制文件夹
        /*File src = new File("D:\\src\\test4");
        File desc = new File("D:\\src\\test6");
        //copyDirectory拷贝的是文件夹内的内容,copy拷贝的是文件夹
        FileUtils.copyToDirectory(src, desc);*/

        //delete删除和clear清空文件夹
//        FileUtils.cleanDirectory(new File("D:\\src\\test6\\test4"));
        FileUtils.deleteDirectory(new File("D:\\src\\test6"));

 hutool工具包

 

//hutool工具的使用
@Test
public void test9(){
    //字符串拼接为file
//        File file = FileUtil.file("D://", "a", "b", "c","a.txt");
//        System.out.println(file);

    //当父文件不存在的时候我们不可以创建,使用hutool就可以了
//        File touch = FileUtil.touch(file);
//        System.out.println(touch);

    //将集合写入文件
    ArrayList<String> arr = new ArrayList<>();
    arr.add("aaa");
    arr.add("aaa");
    arr.add("aaa");
    arr.add("aaa");
//        FileUtil.writeLines(arr,"D:\\workspace\\workspce_idea\\workspace0119\\MyStructure\\YunAlgorithm\\a.txt","UTF-8");
    //向文件后面追加集合
//        File file = FileUtil.appendLines(arr, "D:\\workspace\\workspce_idea\\workspace0119\\MyStructure\\YunAlgorithm\\a.txt", "UTF-8");
    //向文件中读取集合
    ArrayList<String> strings = FileUtil.readLines(new File("D:\\workspace\\workspce_idea\\workspace0119\\MyStructure\\YunAlgorithm\\a.txt"), "UTF-8", new ArrayList<String>());
    System.out.println(strings);
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值