Java基础知识-流

目录

一、流的概念【记忆】

二、流的分类【记忆】

1、方向

1.1、输入流

1.2、输出流

2、处理最小单位

2.1、字节流

2.2、字符流

3、级别

3.1、节点流

3.2、高级流

3.3、高级流为什么效率高

三、File类【掌握】

1、常用构造方法

2、常用方法

3、考题方法

4、例子

四、常用流【掌握】

1、字节流

1.1、常用流

1.2、构造方法

1.3、常用方法

1.3.1、FileInputStream&BufferedInputStream

1.3.2、FileOutputStream&BufferedOutputStream

1.4、例子

1.5、注意事项

2、字符流

2.1、常用流

2.2、构造方法

2.3、常用方法

2.4、例子

2.4.1、读文件

2.4.2、写文件

五、对象流【了解】

1、常用流

2、原型模式

2.1、Score

2.2、Student

2.3、Test

六、数据流【了解】

1、利用DataOutputStream向外写出变量。

2、利用DataInputStream开始读取的程序

七、try-with-resources【掌握】

八、注意事项【掌握】


一、流的概念【记忆】

计算机在运行程序时都是在内存中运行,会将程序需要的数据都加载到内存中,CPU处理数据是和内存进行交互。而内存在断电后存储的数据会消失,所以要长期存储的数据都会存放在硬盘上。硬盘是不能和CPU直接做交互的,那么需要把硬盘的数据先复制到内存中,复制到内存的操作就需要流,反过来长期保存数据也要通过流的操作。流就是用来做数据传输的类,流也只是个名字,不需要纠结为什么叫流。

IO流就是输入输出流,I代表InputStream,O代表OutputStream。

IO流的体系结构

二、流的分类【记忆】

1、方向

相对于内存,分为输入流和输出流。

1.1、输入流

向内存中输入数据是输入流。

1.2、输出流

从内存中把数据输出到硬盘等设备上叫做输出流。

2、处理最小单位

流在处理数据时,按照每次处理的最小单位,可以将流分为字节流和字符流。

2.1、字节流

一次处理最小单位是字节,字节流可以处理所有文件,一般字节流的类都是以Stream结尾的。

2.2、字符流

每次处理的最小单位是字符,因为人直接能读懂的就是字符,所以为了方便开发,做了一个处理字符的流,这种流只能处理纯文本文件,纯文本文件就是用记事本打开能看明白的文件,例如:txt、java、html等。非纯文本文件例如:class、jpg、png、MP3、MP4。

3、级别

3.1、节点流

就是最普通的流,它只有基础功能。

3.2、高级流

在节点流的基础上,进行了拓展和优化,例如增加缓存区、增加更简单操作的方法等,所以在实际开发中应用最多的就是高级流,一般节点流的作用是为了创建高级流。

3.3、高级流为什么效率高

可以对比去水房打水,想装满一个杯子,假如杯子容量是246滴水。用节点流打水相当于每次取一滴水,需要进行246次才能完成,大部分的时间都浪费到路上了。用缓冲区相当于拿了一个小容器,每次可以取30滴水,效率明细提高了。而用高级流相当于拿了一个容量是.100甚至更大的容器取水,是效率最高的方式。

三、File类【掌握】

File表示一个文件或目录,它可以和硬盘上的一个文件或目录建立关系。这个文件或目录可以存在也可以不存在,因为流可以读文件,也可以创建文件。可以通过操作这个File对象获取或者修改对应文件或目录的属性等。

1、常用构造方法

File类有4个构造方法,其中最常用的是参数为一个字符串的构造方法。

File(path):创建一个文件或目录,path是这个文件或目录的路径。

2、常用方法

exists():判断文件或目录是否存在。

getName():获取文件或目录的名字,名字是包含文件拓展名的。

getPath():获取文件或目录的路径。

isDirectory():判断File对象是否是一个目录。

isFile():判断File对象是否是一个文件。

length():返回文件的大小。

listFiles():返回一个File[],表示这个目录下的所有文件。

renameTo(file):将当前的文件对象重命名为file表示的文件。

3、考题方法

delete():删除文件或目录,但是如果目录不为空,那么删除不掉这个目录,如果目录中有目录,那删除不掉这个目录,需要把这个目录中所有的文件删除掉才能删除这个目录。

mkdir():创建这个目录,如果这个目录的父级路径不存在,那么这个目录无法创建。

mkdirs():创建这个目录,无论父级路径(不是单指一层父级,多少层都可以)是否存在,都会创建这个目录,不存在的父级目录会一起创建出来。

4、例子

public static void main(String[] args) {
    System.out.println("两个属性:");
    System.out.println("File.pathSeparator = " + File.pathSeparator);
    System.out.println("File.separator = " + File.separator);
    System.out.println("2、常用方法");
    System.out.println("exists():判断文件或目录是否存在");
    File exists1 = new File("D:/code/test/1");
    System.out.println(exists1.exists());
    File exists2 = new File("D:/code/test/a.txt");
    System.out.println(exists2.exists());
    System.out.println("getName():获取文件或目录的名字");
    File getName = new File("D:\\code\\test\\a.txt");
    System.out.println(getName.getName());
    System.out.println("getPath():获取文件或目录的路径");
    System.out.println(getName.getPath());
    System.out.println("isDirectory():判断File对象是否是一个目录");
    System.out.println(getName.isDirectory());
    System.out.println("isFile():判断File对象是否是一个文件");
    System.out.println(getName.isFile());
    System.out.println("length():返回文件的大小");
    System.out.println(getName.length());
    File file = new File("D:\\code\\test");
    System.out.println(file.length());
    System.out.println("listFiles():返回一个File[],表示这个目录下的所有文件");
    File[] fileArray = file.listFiles();
    for(File f : fileArray){
        System.out.println(f.getName());
    }
    System.out.println("renameTo(file):将当前的文件对象重命名为file表示的文件");
    File img123d = new File("D:\\code\\test\\1\\123的.png");
    File img123 = new File("D:\\code\\test\\1\\123.png");
    img123d.renameTo(img123);
    System.out.println("3、考题方法");
    System.out.println("delete():删除文件或目录,但是如果目录不为空,那么删除不掉这个目录,如果目录中有目录,那删除不掉这个目录,需要把这个目录中所有的文件删除掉才能删除这个目录");
    File dir23 = new File("D:\\code\\test\\1\\23");
    dir23.delete();
    File dir23_png = new File("D:\\code\\test\\1\\23\\1.png");
    dir23_png.delete();
    System.out.println("mkdir():创建这个目录,如果这个目录的父级路径不存在,那么这个目录无法创建");
    File dirMk = new File("D:\\code\\test\\1\\aaa\\bbb");
    dirMk.mkdir();
    System.out.println("mkdirs():创建这个目录,无论父级路径(不是单指一层父级,多少层都可以)是否存在,都会创建这个目录,不存在的父级目录会一起创建出来");
    File dirMks = new File("D:\\code\\test\\1\\ccc\\ddd");
    dirMks.mkdirs();
}
两个属性:
File.pathSeparator = ;
File.separator = \
2、常用方法
exists():判断文件或目录是否存在
true
true
getName():获取文件或目录的名字
a.txt
getPath():获取文件或目录的路径
D:\code\test\a.txt
isDirectory():判断File对象是否是一个目录
false
isFile():判断File对象是否是一个文件
true
length():返回文件的大小
7
0
listFiles():返回一个File[],表示这个目录下的所有文件
1
a.txt
renameTo(file):将当前的文件对象重命名为file表示的文件
3、考题方法
delete():删除文件或目录,但是如果目录不为空,那么删除不掉这个目录,如果目录中有目录,那删除不掉这个目录,需要把这个目录中所有的文件删除掉才能删除这个目录
mkdir():创建这个目录,如果这个目录的父级路径不存在,那么这个目录无法创建
mkdirs():创建这个目录,无论父级路径(不是单指一层父级,多少层都可以)是否存在,都会创建这个目录,不存在的父级目录会一起创建出来

四、常用流【掌握】

1、字节流

1.1、常用流

FileInputStream:处理文件的输入节点流。

BufferedInputStream:高级输入节点流,有缓冲区的。

FileOutputStream:处理文件的输出节点流。

BufferedOutputStream:高级输出节点流,有缓冲区的。

1.2、构造方法

FileInputStream(file):创建一个文件输入流,操作的文件是file

BufferedInputStream(inputStream):通过一个输入流,创建一个高级流,根据多态参数可以传FileInputStream。

FileOutputStream(file):创建一个文件输出流,输出的文件是file。

FileOutputStream(file,append):创建一个文件输出流,和上一个方法不同之处在于append代表了操作这个文件是追加还是覆盖,true代表追加的意思。

BufferedOutputStream(outputStream):通过输出流创建一个高级流,参数是outputStream,输出是否是追加由outputStream决定。

1.3、常用方法

1.3.1、FileInputStream&BufferedInputStream

read(array,int1,int2):读取数据,通过流读取一些数据存放到array数组中,起始位置是int1,读取int2个字节,一般int1都是0,int2会变化。

close():关闭流方法,关闭方法一般写在finally中,要先判断一些是否为空,关闭流要从外向内。

1.3.2、FileOutputStream&BufferedOutputStream

write(array,int1,int2):通过流写数据,将array中int1开始,共int2个字节写出去。

write(array):通过流写数据,相当于write(array,0,array.length)。

close():关闭流。

flush():清空缓存,如果不执行,那么缓存输出流可能有缓存没有写出去,调用这个方法会强制将缓存写出去。如果调用了close方法,会自动调用这个方法。

1.4、例子

public class TestStream {
​
    public static void main(String[] args) {
        File inFile = new File("D:\\code\\test\\a.txt");
        String str = in(inFile);
        System.out.println(str);
        File outFile = new File("D:\\code\\test\\b.txt");
        out(outFile, "lsdjfslkjflsfj你好世界");
        File inCopy = new File("D:\\code\\test\\123.png");
        File outCopy = new File("D:\\code\\test\\456.png");
        copy(inCopy, outCopy);
    }
​
    /**
     * 复制文件
     *
     * @param in  原文件
     * @param out 复制生成的文件
     */
    public static void copy(File in, File out) {
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try {
            bis = new BufferedInputStream(new FileInputStream(in));
            bos = new BufferedOutputStream(new FileOutputStream(out));
            byte[] array = new byte[10];
            int length = bis.read(array, 0, array.length);
            while (length >= 0) {
                bos.write(array, 0, length);
                length = bis.read(array, 0, array.length);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
​
    /**
     * 读取文件方法
     *
     * @param file 目标文件
     * @return 文件内容
     */
    public static String in(File file) {
        String result = "";
        FileInputStream fis = null;
        BufferedInputStream bis = null;
        try {
            fis = new FileInputStream(file);
            bis = new BufferedInputStream(fis);
            List<Object> list = new ArrayList<>();
            byte[] array = new byte[10];
            int length = bis.read(array, 0, array.length);
            while (length >= 0) {
                for (int i = 0; i < length; i++) {
                    list.add(array[i]);
                }
                length = bis.read(array, 0, array.length);
            }
            byte[] arr = new byte[list.size()];
            for (int i = 0; i < list.size(); i++) {
                arr[i] = (byte) list.get(i);
            }
            result = new String(arr, "GBK");
            System.out.println(result.length());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }
​
    /**
     * 创建文件
     *
     * @param out 输出文件
     * @param str 输出内容
     */
    public static void out(File out, String str) {
        FileOutputStream fos = null;
        BufferedOutputStream bos = null;
        try {
            fos = new FileOutputStream(out, true);
            bos = new BufferedOutputStream(fos);
            bos.write(str.getBytes());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

1.5、注意事项

  • 流操作结束后一定要关闭流,在关闭流之前判断是否为空。

  • 读取文件时,在最后可能会因为文件大小导致byte数组没有被填充满,byte数组因为上次读取的数据仍然在数组内,转换的时候会多转换几个byte,文件就不完全一致了。所以每次要存储读取了多少个字节,根据读取到多少自己动态的处理数组中数据。

  • 写文件时也要注意类似于第二点的问题,也要确定输出长度再输出,否则输出的文件和源数据就不一致了。

  • 中文乱码问题。一般导致中文乱码问题的原因有两个,第一个是编码集不统一,需要通过修改编码集解决。第二种是中文占两个字节,读取时这两个字节被分开了,导致转字符串时乱码,这种解决方案只能通过一次性将读取的内容转化成字符串解决。

  • 纯文本文件建议使用字符流,非纯文本文件必须使用字节流。

2、字符流

2.1、常用流

FileReader:文件输入字符流。

FileWriter:文件输出字符流。

BufferedReader:文件输入高级字符流。

BufferedWriter:文件输出高级字符流。

2.2、构造方法

FileReader(file):读取file文件。

FileWriter(file,append):将内容写入到file中,append为true时会做追加操作。

BufferedReader(reader):读取reader流中数据。

BufferedWriter(writer):文件输出。

2.3、常用方法

readLine():输入流,读取一行,返回这行数据的字符串。

write(str):输出流,直接将字符串输出到文件中。

newLine():换行。

2.4、例子

2.4.1、读文件
public class TestReader {
​
    public static void main(String[] args) {
        System.out.println(readGBK(new File("D:\\code\\testReader\\a.txt")));
    }
​
    /**
     * 读取文件
     *
     * @param file 目标文件
     * @return 文件内容
     */
    public static String read(File file) {
        StringBuilder result = new StringBuilder();
        FileReader fr = null;
        BufferedReader br = null;
        try {
            fr = new FileReader(file);
            br = new BufferedReader(fr);
            String str = br.readLine();
            while (str != null) {
                result.append(str + "\n");
                str = br.readLine();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fr != null) {
                try {
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result.toString();
    }
​
    /**
     * 读取GBK编码集文件
     *
     * @param file 目标文件
     * @return 文件内容
     */
    public static String readGBK(File file) {
        StringBuilder result = new StringBuilder();
        FileInputStream fis = null;
        InputStreamReader isr = null;
        BufferedReader br = null;
        try {
            fis = new FileInputStream(file);
            isr = new InputStreamReader(fis, "GBK");
            br = new BufferedReader(isr);
            String str = br.readLine();
            while (str != null) {
                result.append(str + "\n");
                str = br.readLine();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (isr != null) {
                try {
                    isr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result.toString();
    }
​
}
2.4.2、写文件
public class TestWriter {
​
    public static void main(String[] args) {
        String str = "asdfasdfasljsdlfjslkfjlsf5154654654654\n" +
                "35ds44sf46sdf645sd456\n" +
                "sd45fs123d\n" +
                "sf2.s12\n" +
                "今天星期六\n" +
                "13sf";
        write(new File("D:\\code\\testReader\\b.txt"), str);
    }
​
    /**
     * 写文件
     *
     * @param file 输出文件
     * @param str  输出内容
     */
    public static void write(File file, String str) {
        FileWriter fw = null;
        BufferedWriter bw = null;
        try {
            fw = new FileWriter(file);
            bw = new BufferedWriter(fw);
            bw.write(str);
            bw.newLine();
            bw.newLine();
            bw.newLine();
            bw.newLine();
            bw.newLine();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bw != null) {
                try {
                    bw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fw != null) {
                try {
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

五、对象流【了解】

对象流是用于针对对象输入或者输出的,输入可能从硬盘中读取数据,也可能从内存中读取数据。输出同理,可能输出到硬盘上,也可能输出到内存中。

1、常用流

ObjectInputStream:对象输入流。

ObjectOutputStream:对象输出流。

ByteArrayInputStream:字节数组输入流。

ByteArrayOutputStream:字节数组输出流。

2、原型模式

原型模式是一种创建型设计模式,Prototype模式允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节,工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建。

2.1、Score

public class Score implements Serializable {
​
    private String name;
    private int score;
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    public int getScore() {
        return score;
    }
​
    public void setScore(int score) {
        this.score = score;
    }
​
    @Override
    public String toString() {
        return "Score{" +
                "name='" + name + '\'' +
                ", score=" + score +
                '}';
    }
}

2.2、Student

public class Student implements Cloneable, Serializable{
​
    private String name;
    private Score score;
    private int age;
​
    @Override
    public Student clone() throws CloneNotSupportedException {
        ObjectInputStream ois = null;
        ObjectOutputStream oos = null;
        ByteArrayInputStream bais = null;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
​
        try {
            oos = new ObjectOutputStream(baos);
            oos.writeObject(this);
            bais = new ByteArrayInputStream(baos.toByteArray());
            ois = new ObjectInputStream(bais);
            return (Student) ois.readObject();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    public Score getScore() {
        return score;
    }
​
    public void setScore(Score score) {
        this.score = score;
    }
​
    public int getAge() {
        return age;
    }
​
    public void setAge(int age) {
        this.age = age;
    }
​
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", score=" + score +
                ", age=" + age +
                '}';
    }
}

2.3、Test

public class Test {
​
    public static void main(String[] args) throws CloneNotSupportedException {
        Student s1 = new Student();
        s1.setAge(10);
        s1.setName("zhangsan");
        Score score = new Score();
        score.setName("math");
        score.setScore(90);
        s1.setScore(score);
        System.out.println(s1);
        System.out.println(s1.hashCode());
​
        Student s2 = s1.clone();
        System.out.println(s2);
        System.out.println(s2.hashCode());
​
        s1.getScore().setScore(50);
​
        System.out.println(s1.getScore());
        System.out.println(s2.getScore());
        System.out.println(s1.getScore() == s2.getScore());
    }
​
}

六、数据流【了解】

包括DataInputStream、DataOutputStream等,用来操作基本数据类型和字符串的。

DataInputStream:将文件中存储的基本数据类型和字符串写入内存的变量中。

DataOutputStream:将内存中的基本数据类型和字符串的变量写出文件中。

1、利用DataOutputStream向外写出变量。

public class Test01 {
    /*这是一个main方法,是程序的入口*/
    public static void main(String[] args) throws IOException {
        /*
        * DataOutputStream:将内存中的基本数据类型和字符串的变量写出文件中
        * File f = new File("d:\\Demo2.txt");
        * FileOutputStream fos = new FileOutputStream(f);
        * DataOutputStream dos = new DataOutputStream(fos);
        */
        DataOutputStream dos = new DataOutputStream(new FileOutputStream(new File("d:\\Demo2.txt")));
        /*向外将变量写到文件中去*/
        dos.writeUTF("你好");
        dos.writeBoolean(false);
        dos.writeDouble(6.9);
        dos.writeInt(82);
        /*关闭流*/
        dos.close();
    }
}

在Demo2.txt文件中,我们看到:

这个内容我们看不懂,是给程序看的。

2、利用DataInputStream开始读取的程序

public class Test02 {
    /*这是一个main方法,是程序的入口*/
    public static void main(String[] args) throws IOException {
        /*DataInputStream:将文件中存储的基本数据类型和字符串写入内存的变量中*/
        DataInputStream dis = new DataInputStream(new FileInputStream(new File("d:\\Demo2.txt")));
        /*将文件中内容读取到程序中来*/
        System.out.println(dis.readUTF());
        System.out.println(dis.readBoolean());
        System.out.println(dis.readDouble());
        System.out.println(dis.readInt());
        /*关闭流*/
        dis.close();
    }
}

结果:

验证:那个文件,我们看不懂,程序看得懂。

要求:写出的类型跟读入的类型必须要匹配!

七、try-with-resources【掌握】

JDK1.7开始增加了对需要关闭的资源管理处理的特殊语法try-with-resources。

try(资源变量=创建资源对象){
​
} catch(XXXException e){
​
}

其中资源对象需要实现AutoCloseable接口,例如:inputStream、outputStream、Connection、statement、Result等接口都实现了AutoCloseable,使用try-with-resources可以不写finally语句,编译器会帮助生成关闭资源代码,更推荐这种写法,代码简洁,可读性也更强。

try (FileInputStream fis = new FileInputStream(file)){
    fis.read(fileContent);
} catch (IOException e) {
    e.printStackTrace();
}

八、注意事项【掌握】

  • 字符流不能处理非纯文本文件,字节流可以处理所有文件。纯文本文件就是记事本打开可以看明白的文件,例如txt、html、css、Java,非纯文本文件例如:MP3、MP4、jpg、png、doc等。

  • 流用完一定要记得关闭,尤其是高级流,如果不关闭会出现问题,缓冲区的数据可能不会被处理到。flush方法可以处理缓存,close调用了它,我们常用close方法,彻底关闭不用的流。

  • 处理纯文本文件建议用字符流,比较简单。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值