java文件和流

字节流

当不同的介质之间有数据交互的时候,JAVA就使用流来实现。
数据源可以是文件,还可以是数据库,网络甚至是其他的程序

比如读取文件的数据到程序中,站在程序的角度来看,就叫做输入流
输入流: InputStream
输出流:OutputStream

InputStream字节输入流
OutputStream字节输出流
用于以字节的形式读取和写入数据

所有的流,无论是输入流还是输出流,使用完毕之后,都应该关闭。 如果不关闭,会产生对资源占用的浪费。 当量比较大的时候,会影响到业务的正常开展。
关闭流的方法有以下:

  1. 在try中关闭

    在try的作用域里关闭文件输入流有一个弊端;
    如果文件不存在,或者读取的时候出现问题而抛出异常,那么就不会执行这一行关闭流的代码,存在巨大的资源占用隐患。
    
  2. 在finally中关闭

    这是标准的关闭流的方式
    1). 首先把流的引用声明在try的外面,如果声明在try里面,其作用域无法抵达finally.
    2). 在finally关闭之前,要先判断该引用是否为空
    3). 关闭的时候,需要再一次进行try catch处理
    
    public static void fileSplit(File file, int everyLength) {
        
        if (file.length() == 0) {
            System.out.println("file length is 0");
        }
        
        byte[] all = new byte[(int) file.length()];
        FileInputStream in = null;
        try {
            in = new FileInputStream(file);
            in.read(all);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            if (in != null)
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
        
        int fileNumber;
        if (all.length / everyLength == 0) {
            fileNumber = (int) (all.length / everyLength);
        } else {
            fileNumber = (int) (all.length / everyLength) + 1;
        }
        
        for (int i = 0; i < fileNumber; i++) {
            String fileName = file.getName() + "-" + i;
            File newFile = new File(file.getParent(), fileName);
            FileOutputStream write = null;
            try {
                byte[] everyContent = new byte[everyLength];
                if (i != fileNumber - 1) {
                    everyContent = Arrays.copyOfRange(all, i*everyLength, everyLength*(i+1));
                } else {
                    everyContent = Arrays.copyOfRange(all, i*everyLength, all.length);
                }
                write = new FileOutputStream(newFile);
                write.write(everyContent);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } finally {
                if (write != null) {
                    try {
                        write.close();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        }
    }}

    public static void fileMerge(String dir, String fileName) {
        
        File destFile = new File(dir, "merge.exe");
        FileOutputStream out = null;
        FileInputStream in = null;
        try {
            out = new FileOutputStream(destFile);
            int idx = 0;
            while(true) {
                File srcFile = new File(dir, fileName + "-" + idx++);
                byte[] eachContent = new byte[(int) srcFile.length()];
                if (! srcFile.exists())
                    break;
                try {
                    in = new FileInputStream(srcFile);
                    in.read(eachContent);
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    if (in != null)
                    in.close();
                }
                out.write(eachContent);
                out.flush();
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }

这是标准的严谨的关闭流的方式,但是看上去很繁琐,所以写不重要的或者测试代码的时候,都会采用上面的有隐患try的方式,因为不麻烦~

  1. 使用try()的方式

    把流定义在try()里,try,catch或者finally结束的时候,会自动关闭
    这种编写代码的方式叫做 try-with-resources, 这是从JDK7开始支持的技术
    

所有的流,都实现了一个接口叫做 AutoCloseable,任何类实现了这个接口,都可以在try()中进行实例化。 并且在try, catch, finally结束的时候自动关闭,回收相关资源。

    public static void testCloseTry(File file) {
        
        //把流定义在try()里,try,catch或者finally结束的时候,会自动关闭
        try (FileInputStream fis = new FileInputStream(file)) {
            byte[] all = new byte[(int) file.length()];
            fis.read(all);
            for (byte b : all) {
                System.out.println(b);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

字符流

Reader字符输入流
Writer字符输出流
专门用于字符的形式读取和写入数据

加解密

加密算法:
数字: 如果不是9的数字,在原来的基础上加1,比如5变成6, 3变成4 如果是9的数字,变成0
字母字符: 如果是非z字符,向右移动一个,比如d变成e, G变成H
如果是z,z->a, Z-A。 字符需要保留大小写 非字母字符 比如’,&^保留不变,中文也保留不变
解密算法:
数字:如果不是0的数字,在原来的基础上减1,比如6变成5, 4变成3
如果是0的数字,变成9
字母字符:如果是非a字符,向左移动一个,比如e变成d, H变成G
如果是a,a->z, A-Z。字符需要保留大小写
非字母字符:比如’,&^ 保留不变,中文也保留不变

package com.test.how2j;

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class TestEncodeAndDescode {

    public static void main(String[] args) {
        File encodingFile = new File("D:/file/encoding.txt");
        File encodedFile = new File("D:/file/encoded.txt");
        File descodedFile = new File("D:/file/descoded.txt");
        encodeFile(encodingFile, encodedFile);
        decodeFile(encodedFile, descodedFile);
    }

    /*
     * 在这个方法中把decodingFile的内容进行解密,然后保存到decodedFile文件中。 解密算法: 数字:
     * 如果不是0的数字,在原来的基础上减1,比如6变成5, 4变成3 如果是0的数字,变成9 字母字符: 如果是非a字符,向左移动一个,比如e变成d,
     * H变成G 如果是a,a->z, A-Z。 字符需要保留大小写 非字母字符: 比如',&^ 保留不变,中文也保留不变
     */
    public static void encodeFile(File encodingFile, File encodedFile) {
        FileReader in = null;
        FileWriter out = null;
        try {
            in = new FileReader(encodingFile);
            out = new FileWriter(encodedFile);

            char[] inContent = new char[(int) encodingFile.length()];
            in.read(inContent);
            System.out.println("加密前的内容:");
            System.out.println(new String(inContent));
            encode(inContent);
            System.out.println("加密后的内容:");
            System.out.println(new String(inContent));

            out.write(inContent);
            out.flush();

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                if (in != null)
                    in.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            try {
                if (out != null)
                    out.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    /*
     * 在这个方法中把decodingFile的内容进行解密,然后保存到decodedFile文件中。 解密算法: 数字:
     * 如果不是0的数字,在原来的基础上减1,比如6变成5, 4变成3 如果是0的数字,变成9 字母字符: 如果是非a字符,向左移动一个,比如e变成d,
     * H变成G 如果是a,a->z, A-Z。 字符需要保留大小写 非字母字符: 比如',&^ 保留不变,中文也保留不变
     */
    public static void decodeFile(File decodingFile, File decodedFile) {
        FileReader in = null;
        FileWriter out = null;
        try {
            in = new FileReader(decodingFile);
            out = new FileWriter(decodedFile);

            char[] inContent = new char[(int) decodingFile.length()];
            in.read(inContent);
            System.out.println("解密前的内容:");
            System.out.println(new String(inContent));
            descode(inContent);
            System.out.println("解密后的内容:");
            System.out.println(new String(inContent));

            out.write(inContent);

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                if (in != null)
                    in.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            try {
                if (out != null)
                    out.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    public static void encode(char[] cbuf) {
        for (int i = 0; i < cbuf.length; i++) {
            char c = cbuf[i];
            if (isLetterOrDigit(c)) {
                switch (c) {
                case '9':
                    c = '0';
                    break;
                case 'z':
                    c = 'a';
                    break;
                case 'Z':
                    c = 'A';
                    break;
                default:
                    c++;
                    break;
                }
                cbuf[i] = c;
            }
        }
    }

    public static void descode(char[] cbuf) {
        for (int i = 0; i < cbuf.length; i++) {
            char c = cbuf[i];
            if (isLetterOrDigit(c)) {
                switch (c) {
                case '0':
                    c = '9';
                    break;
                case 'a':
                    c = 'z';
                    break;
                case 'A':
                    c = 'Z';
                    break;
                default:
                    c--;
                    break;
                }
                cbuf[i] = c;
            }
        }
    }

    public static boolean isLetterOrDigit(char c) {
        // 不使用Character类的isLetterOrDigit方法是因为,中文也会被判断为字母
        String letterOrDigital = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
        return -1 == letterOrDigital.indexOf(c) ? false : true;
    }

}

缓存流

以介质是硬盘为例,字节流和字符流的弊端: 在每一次读写的时候,都会访问硬盘。 如果读写的频率比较高的时候,其性能表现不佳。

为了解决以上弊端,采用缓存流。
缓存流在读取的时候,会一次性读较多的数据到缓存中,以后每一次的读取,都是在缓存中访问,直到缓存中的数据读取完毕,再到硬盘中区读取。

就好比吃饭,不用缓存就是每吃一口都到锅里去铲。用缓存就是先把饭盛到碗里,碗里的吃完了,再到锅里去铲

缓存流在写入数据的时候,会先把数据写入到缓存区,直到缓存区达到一定的量,才把这些数据,一起写入到硬盘中去。按照这种操作模式,就不会像字节流,字符流那样每写一个字节都访问硬盘,从而减少了IO操作。

1. 使用缓存流读取数据

缓存字符输入流 BufferedReader 可以一次读取一行数据

    public static void testReader(File file) {
        try (FileReader in = new FileReader(file); BufferedReader br = new BufferedReader(in);) {
            while (true) {
                String line = br.readLine();
                if (line == null)
                    break;
                System.out.println(line);
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

2. 使用缓存流写出数据,并使用flush刷新文件内容

PrintWriter 缓存字符输出流, 可以一次写出一行数据
有的时候,需要立即把数据写入到硬盘,而不是等缓存满了才写出去。 这时候就需要用到flush

    public static void testWrite(File file) {
        FileWriter fw = null;
        BufferedWriter bw  = null;
        PrintWriter pw = null;
        
        try {
            fw = new FileWriter(file);
            bw = new BufferedWriter(fw);
            pw = new PrintWriter(fw);
            
            bw.write("hello\n");
            bw.flush();
            
            pw.println("this is print write test.");
            pw.flush();
            pw.println("this is print write test2.");
            pw.flush();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                if (fw != null) {
                    fw.close();
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            try {
                if (bw != null) {
                    bw.close();
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        
    }

数据流

DataInputStream 数据输入流
DataOutputStream 数据输出流

直接进行字符串的读写
使用数据流的writeUTF()和readUTF() 可以进行数据的格式化顺序读写

    public static void write(File file) {

        try (FileOutputStream out = new FileOutputStream(file); DataOutputStream dos = new DataOutputStream(out);) {
            dos.writeBoolean(true);
            dos.writeInt(10);
            dos.writeUTF("test");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static void read(File file) {
    
        try (FileInputStream in = new FileInputStream(file); DataInputStream dis = new DataInputStream(in);) {
            System.out.println("读到布尔型: " + dis.readBoolean());
            System.out.println("读到int类型: " + dis.readInt());
            System.out.println("读到字符串类型:" + dis.readUTF());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

对象流

对象流指的是可以直接把一个对象以流的形式传输给其他的介质,比如硬盘
一个对象以流的形式进行传输,叫做序列化。 该对象所对应的类,必须是实现Serializable接口

序列化一个对象

public class Student implements Serializable {

    private static final long serialVersionUID = -6955047867001941524L;
    public int id;
    public String name;
    public String sex;
}
    public static void objStream(File file, Student obj) {

        try (FileOutputStream out = new FileOutputStream(file);
                ObjectOutputStream oos = new ObjectOutputStream(out);
                FileInputStream in = new FileInputStream(file);
                ObjectInputStream ois = new ObjectInputStream(in);) {
            oos.writeObject(obj);
            Student s = (Student) ois.readObject();
            System.out.println(s.id);
            System.out.println(s.name);
            System.out.println(s.sex);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

System.in和System.out

System.out 是常用的在控制台输出数据的
System.in可以从控制台输入数据

System.in输入字符串Scanner读取字符串

package com.test.how2j;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;

public class TestScanner {

    public static void main(String[] args) {
//        sysIn();
//        scanner();
        classMaker();
//        System.out.println(String.format("test %s", "123", "\n"));
    }
    
    public static void sysIn() {
        
        try (InputStream is = System.in;) {
            System.out.println(is.read());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    public static void scanner() {
        
        Scanner s = new Scanner(System.in);
        while(true) {
            String str = s.nextLine();
            System.out.println("所读数据是:" + str);
        }
    }
    
    public static void classMaker() {
        Scanner s = new Scanner(System.in);
        
        System.out.println("请输入类名:");
        String className = s.nextLine();
        s.nextLine();
        System.out.println("请输入属性类型:");
        String type = s.nextLine();
        s.nextLine();
        System.out.println("请输入属性名称:");
        String name = s.nextLine();
        s.nextLine();
        
        File file = new File("D:/file/" + className + ".java");
        try (FileWriter fw = new FileWriter(file)) {
            String str = "public class " + className + " {" + "\n";
            str += "    public " + type + " " + name + ";\n";
            str += "    public " + className + "()" + "{\n    }" + "\n";
            str += "\n";
            str += "    public void set" + nameMaker(name) + "(" + type + " " + name + ")" + "{\n";
            str += "        this."  + name + " = " + name + ";\n";
            str += "    }";
            str += "\n\n";
            str += "    public " + type + " get" + nameMaker(name) + "() {\n";
            str += "        return " + name + ";\n";
            str += "    }\n";
            str += "}";
            
            fw.write(str);
            fw.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    public static String nameMaker(String str) {
        char[] c = str.toCharArray();

        StringBuffer sb = new StringBuffer();
        sb.append(String.valueOf(String.valueOf(c[0]).charAt(0)).toUpperCase());
        sb.append(str.substring(1));
        return sb.toString();
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值