重温JavaSE17、18

复习(偏重点)

java.sql.Date和java.util.Date的联系和区别
  1. 都代表一个时间类型,util代表java程序中的时间类型、sql是数据库对接的时间类型
  2. 父类:util.Date,子类sql.Date
  3. 精确度不一样,util.Date到年月日时分秒,sql.Date只到年月日
  4. String类型转换成日期类型:(后面会常用)

sql.Date可通过方法valueOf(“年-月-日”)进行字符串的转换。

util.Date通过SimpleDateFormat对象的parse(“时分秒年月日”);方法进行字符串的转换

File类(偏重点,要会用)

可对目录(文件夹)或文件进行一些列操作(不包括文件内容的操作)

文件目录分隔符:

File.separator、\\、/

文件实例化:
实例化方法说明
File file = new File(目录或文件的路径)直接创建文件对象
File file = new File(目录路径+“\\”+目录或文件名);目录后拼接一个文件名
File file = new File(目录路径+File.separator+目录或文件名);目录后拼接一个文件名
File file = new File(目录路径,目录或文件名);目录后拼接一个文件名,省去上面那种打/了
可直接输出查看文件路径,或exists查看文件是否存在
文件对象的方法:
实例化文件对象后的方法说明:要在实例化File f = new File(文件路径);之后再用f.进行调用返回值
获取功能:
getAbsolutePath()返回File的绝对路径名String
getPath()将此File转换为路径名(实例化时的值)String
getName()返回此File表示的文件或目录的名称,不包含上级文件String
length()返回此File表示的文件的字节大小,不能获取目录的字节大小long
getParent()返回此File表示的父目录的路径名字符串,没有则nullString
toString()返回此File表示的路径字符串String
判断功能:
exists()此File标识的文件或目录是否实际存在boolean
isDirectory()此File标识的是否为文件夹(目录)boolean
isFile()此File表示的是否为文件boolean
isHidden()此File表示的是否为隐藏的文件或目录boolean
canWrite()此File表示的文件或目录是否可写boolean
canRead()此File表示的文件或目录是否可读boolean
equals(Object obj)将指定对象与调用函数的对象进行比较boolean
删除和创建
createNewFile()仅当不存在该名称的文件时,创建一个新的空文件,不存在返回falseboolean
mkdir()创建由File表示的目录boolean
mkdirs()创建由File表示的目录,包括任何必须但不存在的父目录boolean
delete()删除由此File表示的文件或目录
只能删除文件或者空目录,不能删除非空目录
boolean
renameTo(new File(x))更改文件位置到x下void
遍历
list()返回一个String数组,表示该File目录中的所有子文件或目录的名称String[]
listFiles()返回一个File数组,表示File目录中的所有子文件或目录的路径File[]

看下面代码:

@Test
public void test01() {
    //字符串中路径的写法:
    //        File file = new File("D:\\用户-常\\Desktop\\test.txt");
    //        File file1 = new File("D:/用户-常/Desktop/test.txt");
    File file2 = new File("D:"+File.separator+"用户-常"+File.separator+"Desktop"+File.separator+"test.txt");//自动添加路径,不确定是什么平台时用
    System.out.println(file2.getName());//获取文件名
    System.out.println(file2.getPath());//获取文件路径
    System.out.println(file2.getParent());//获取上层文件路径
    System.out.println(file2.length());//长度
    System.out.println(file2.exists());//是否存在
    System.out.println(file2.isFile());//是不是文件(false是文件夹)
    System.out.println(file2.isDirectory());//是不是文件夹(false是文件)
}
//例子:给一个路径,将该路径下的所有文件和子目录(缩进后输出子文件)
@Test
public void test02(){
    show(0,"D:\\13214");
}
public static void show(int level, String url){//目录才行
    File file = new File(url);
    if (file.isDirectory()){
        File[] files = file.listFiles();//该目录下的所有文件和目录
        for (File f: files) {//获取每个子文件和子目录
            for (int i = 0; i < level; i++) {//遍历进行缩进
                System.out.print("\t");
            }
            System.out.println(f);//输出文件名
            if (f.isDirectory()){
                show(level+1,f.getAbsolutePath());//传入绝对路径
            }
        }
    }
}

IO流(重点)

关闭流要求:一定要关闭输入输出流,满足后开的先关,先开的最后关不要关错流,不关会一直占用内存

学习IO流是为了文件的上传和下载

​ 数据库存(严格符合要求的标准数据):变量、数组、集合等信息
​ 文件里存(可通过IO流读与写文件数据):图片、视频、文本等信息

(后期文件和下载有指定的工具类,不用写IO流,直接读取服务器的数据,写入到自己本地)

什么是IO流?
input:输入流(读)
output:输出流(写)
流:管道(位于内存和物理文件之间输送信息),可持续化数据

IO流的步骤:
  1. 获得源数据对象(创建一个File类的对象,还可能是别的对象)
  2. 创建流,(创建一个输入或输出流的对象)
  3. 让流和源数据对象相连(流(源数据对象),在输出流的源数据对象后true追加写入,否则会清空原内容)
  4. 通过流进行读和写文件(输入流对象的read()/输出流的write()方法)
  5. 关闭流(各种流对象的close(); )

节点流(重点)

输入流的优点:(网上找的)

  • 是Java标准库中提供的类,可以很方便地读取文本文件中的数据。

输入流的缺点:(网上找的)

  • 在读取文件时,文件必须存在,否则会抛出FileNotFoundException异常。

输出流的优点:(网上找的)

  • 它可以非常方便地将数据写入文件中。

输出流的缺点:(网上找的)

  • 如果文件不存在会自动创建一个新文件。
字节流

以字节为单位进行数据操作,一般用来处理图片、视频、音频PPT、Word等类型的文件。(二进制,8位字节为单元)

字节输入流FileInputStream(读)
构造方法(不能有中文)说明
FileInputStream fi = new FileInputStream(String fileName)接受一个文件名字符串来创建一个FileInputStream对象
FileInputStream fi = new FileInputStream(File file)接受一个File对象来创建一个FileInputStream对象
FileInputStream方法说明返回值
read()读取一个数据字节,如果已经到达文件末尾,返回-1int
read(byte[] b)将最多 b.length 个字节的数据读入到数组b中int
read(byte[] b,int off,int len);off开始读取len个字节的数据读入到数组b中int
close()关闭输入流void
available()从此输入流中读取的剩余字节数,大于0则输入流中有内容
可用于遍历的条件判断,有缓冲流连要用缓冲流的(要少用)
int

转字符串:

String sum = "";
int i;
while((i = fi.read()) != -1) {
    sum += (char) i;
}
字节输出流FileOutputStream(写)

可在最后加true表示在文件末尾追加写入(不覆盖)默认为false注意:不写true就会清空文件内容`

构造方法(不能有中文)说明
FileOutputStream fo = new FileInputStream(String fileName[,true])接受一个文件名字符串来创建一个FileOutputStream对象,(true追加,否则会清空文件内容)
FileOutputStream fo = new FileOutputStream(File file[,true])接受一个File对象来创建一个FileOutputStream对象,(true追加,否则会清空文件内容)
FileOutputStream方法说明返回值
write(int b)将单个字节写入流中void
write(byte[] b)将字节数组指定位置的子数组写入到流中void
write(byte[] b,int off,int len)将字节数组指定位置的子串写入到流中void
flush()仅仅是刷新缓冲区,强制写出缓冲区的数据void
close()关闭输出流void
字符流

以字符为单位进行数据操作,一般用来处理纯文本类型的文件,如.txt文件等,无法直接写入字节数据

字符输入流FileReader(读)
构造方法FileReader说明
FileReader fr = new FileReader(String fileName)接受一个文件名字符串来创建一个FileReader对象
FileReader fr = new FileReader(File file)接受一个File对象来创建一个FileReader对象
FileReader方法说明:必须按上面实例化之后返回值
read()会返回读取到的字符编码,如果已经到达文件末尾,返回-1int
read(char[] ch)这个方法会读取长度为ch.length的字符到cbuf中,并返回读取的字符个数int
close()关闭输入流void
字符输出流FileWriter(写)

可在最后加true表示在文件末尾追加写入(不覆盖)默认为false注意:不写true就会清空文件内容`

构造方法说明
FileWriter(File file[,true])接受一个File对象,创建一个新的文件写入流,如果该文件已经存在,将被覆盖。(true追加,否则会清空文件内容)
FileWriter(String fileName[,true])接受一个文件名字符串,创建一个新的文件写入流,如果该文件已经存在,将被覆盖。(true追加,否则会清空文件内容)
FileWriter(File file, boolean append[,true])可以设置是否追加内容到文件末尾,(true追加,否则会清空文件内容)
FileWriter(String fileName, boolean append[,true])可以设置是否追加内容到文件末尾,(true追加,否则会清空文件内容)
FileWriter(FileDescriptor fd[,true])创建一个与已存在文件关联的文件写入流。(true追加,否则会清空文件内容)
FileWriter方法更多操作方法说明:必须按上面实例化之后返回值
write(int c)将单个字符(根据ascii码转的)写入流中void
write(char[] ch, int off, int len)将字符数组指定位置的子数组写入到流中void
write(String str, int off, int len)将字符串指定位置的子串写入到流中void
flush()仅仅是刷新缓冲区,强制写出缓冲区的数据void
close()关闭输出流void

自写快捷循环语句:

for(int i = 输入流对象.read();i != -1;i = 输入流对象.read()){
System.out.print((char)i);
}

快捷创建循环
在这里插入图片描述

close()flush()的区别:
  • ``close()是关闭流对象,但是会先刷新一次缓冲区,关闭之后,流对象不可以继续再使用了,否则报空指针异常。
  • ``flush()仅仅是刷新缓冲区,准确的说是**"强制写出缓冲区的数据"**,流对象还可以继续使用。

看下面字节流读取和写入的步骤:

//例1:读取文件下的内容
@Test
public void test01() throws IOException {
    //获得数据源对象
    File file = new File("D:/用户-常/Desktop/test.txt");
    //创建一个流并连接数据源:
    //从外部物理文件读入到内存里,用输入流
    //文件里都是字母和数字,没有汉字,就用字节流
    //不需要额外功能,选择用节点流
    //        FileReader fileReader = new FileReader(file);//能读取汉字
    FileInputStream fileInputStream = new FileInputStream(file);//流连接到数据源
    //读取一个字符
    int read = fileInputStream.read();
    //循环读取全部内容,含回车
    while (read != -1){
        System.out.print((char)read);
        read = fileInputStream.read();
    }
    /*下面代码代表上面循环的几行
    for(int read = fileInputStream.read();read != -1;read = fileInputStream.read()){
                System.out.print((char)read);
            }*/
    //关闭流
    fileInputStream.close();
}
//例2:控制台接收内容,将内容写入到文件里
@Test
public void test02() throws IOException {
    //获得数据源对象
    File file = new File("D:/用户-常/Desktop/test.txt");
    //创建一个流并连接数据源:
    FileOutputStream fileOutputStream = new FileOutputStream(file,true);//流连接到数据源,true是追加输入(不覆盖)
    //提示信息,接收控制台输入的信息
    System.out.println("请输入内容(不能为汉字):");
    String str = new Scanner(System.in).next();
    //接收信息,写入到数据源对象里,(会覆盖文件原内容)
    fileOutputStream.write(str.getBytes());
    //关闭流
    fileOutputStream.close();
    System.out.println("写入成功");
}

看下面字符流读取和写入的步骤:

@Test
public void test01() throws IOException {
    FileReader fileReader = null;
    try {
        //获取数据源对象:
        File file = new File("D:/用户-常/Desktop/test.txt");
        //创建流,读取文本要用字符流
        //读取视频图片音频要用字节流
        fileReader = new FileReader(file);
        //读取数据
        int read = fileReader.read();
        while (read != -1){
            System.out.print((char)read);
            read = fileReader.read();
        }
    } catch (IOException e) {
        throw new RuntimeException(e);
    }finally {
        //关闭流
        fileReader.close();
    }
}
//字符输出流一样
@Test
public void test02() throws IOException {
    FileWriter fileWriter = null;
    try {
        File file = new File("D:/用户-常/Desktop/test.txt");
        fileWriter = new FileWriter(file,true);//追加输入
        fileWriter.write("\n哈哈哈");
    } catch (IOException e) {
        throw new RuntimeException(e);
    }finally {
        fileWriter.close();
    }
}

处理流之缓冲流(偏重点)

缓冲流就是为字节、字符流提速的工具

是为高效率而设计的 (以前是一个字节一个字节的读,现在可以控制一起读)

缓冲字节流缓冲字符流
缓冲字节输入流BufferedInputStream(读)缓冲字符输入流BufferedReader(读)
缓冲字节输出流BufferedOutputStream(写)缓冲字符输出流BufferedWriter(写)

每个的构造方法都是传入对应的输入输出流对象(套娃)

例:

BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:123/t.txt"));
BufferedOutputStream bos =new BufferedOutputStream(new FileOutputStream("D:t.txt",true));
BufferedReader br = new BufferedReader(new FileReader("D:123/t.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("D:123/t.txt",true));
缓冲输入流的遍历方法:
for(int s = 缓冲输入流对象.read(); s!=-1; s = 缓冲输入流对象.read()){
    System.out.print((charbyte)s);
}

byte[] bytes = new byte[自定义大小];
while (缓冲输入流.read(bytes) != -1){
    缓冲输出流.write(bytes);//这行一般都是bytes的操作
}
//下面少用,本地用可以
byte[] bytes = new byte[自定义大小];
while (BufferedInputStream对象.available() > 0){//只能BufferedInputStream对象使用
    缓冲输出流.write(bytes,0,缓冲输入流.read(bytes));
}
特殊:(了解)

实例化时可以指定缓冲区大小

BufferedInputStream(InputStream in, int size)
BufferedOutputStream(OutputStream out, int size)
BufferedReader(Reader in, int sz)
BufferedWriter(Writer out, int sz)

BufferedInputStream也有available()方法,上上个代码就是,(有点可能有bug少用)

特殊:
BufferedReader br = new BufferedReader(new FileReader("D:123/t.txt"));
for(String s = br.readLine(); s!=null; s = br.readLine()){//按行读取,不读换行符
    System.out.println(s);
}

BufferedWriter的换行符bw.newLine(); 写一行分隔符,由系统属性定义符号

看下面缓冲字节流的复制图片的代码:

@Test
public void test01() throws IOException {//就测试一下,没写trycatch
    File file = new File("D:\\用户-常\\Desktop\\test.jpg");
    File file2 = new File("D:\\用户-常\\Desktop\\新建文件夹\\test.jpg");
    FileInputStream fileInputStream = new FileInputStream(file);//流连接到数据源
    FileOutputStream fileOutputStream = new FileOutputStream(file2,true);//流连接到数据源,true是追加输入(不覆盖)
    //创建处理流管道:
    BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);//设置缓冲区大小
    BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
    byte[] bytes = new byte[1000000];
    while (bufferedInputStream.read(bytes) != -1){
        bufferedOutputStream.write(bytes);
    }
    //关闭流,关闭要求:后开的先关,先开的最后关
    bufferedOutputStream.close();
    bufferedInputStream.close();
    fileOutputStream.close();
    fileInputStream.close();
    System.out.println("复制成功");
}

看下面自己写的BufferedReader和BufferedWriter使用方法

@Test
public void test02() throws IOException {
    BufferedReader br = null;
    BufferedWriter bw = null;
    try {
        br = new BufferedReader(new FileReader("D:/用户-常/Desktop/test.txt"),1024);
        bw = new BufferedWriter(new FileWriter("D:/用户-常/Desktop/test.txt",true));
        for(String s = br.readLine(); s!=null; s = br.readLine()){//按行读取,不读换行符
            System.out.println(s);
        }

        /*for(int s = br.read(); s!=-1; s = br.read()){
            System.out.print((char)s);
        }*/
        char[] chars = "asjdoasjdiojasid".toCharArray();
        bw.newLine();//换行
        bw.write(chars);
    } catch (IOException e) {
        throw new RuntimeException(e);
    } finally {
        bw.close();
        br.close();
    }
}

保存控制台输入的信息到文件里,按行实时转入:

@Test
public void test() throws IOException {//保存控制台输入的信息
    BufferedWriter bw = null;//设置了缓冲区
    try {
        bw = (new BufferedWriter(new FileWriter("D:\\用户-常\\Desktop\\t.txt",true),1024));

        Scanner sc = new Scanner(System.in);
        System.out.println("请输入要保存的文件内容,输入exit退出");
        String str = sc.next();
        while (!"exit".equals(str)){
            bw.write(str);
            bw.newLine();//换行
            str = sc.next();
            bw.flush();//弹出缓冲区的内容,观察t.txt文件每次输入都有信息录入进去
        }
    } catch (IOException e) {
        throw new RuntimeException(e);
    }finally {
        bw.close();
    }
}

一个字节一个字节的方式、不使用缓冲字节输入输出流的方式一次读取多个字节、使用缓冲字节输入输出流

下面代码参考:[[Java IO流之缓冲流(深入浅出学习) - LeeHua - 博客园 (cnblogs.com)](https://www.cnblogs.com/liyihua/p/12269827.html)]

/**
 * 不使用缓冲字节输入输出流,
 * 一个一个字节的方式。(最慢)
 */
public static void method1() throws IOException {//没用trycatch
    FileInputStream fis = new FileInputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo33/test.jpg");
    FileOutputStream fos = new FileOutputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo33/copy1.jpg");
 
    int len = 0;
    while ((len = fis.read()) != -1) {
        fos.write(len);
    }
 
    fis.close();
    fos.close();
}
/**
 * 不使用缓冲字节输入输出流,
 * 一次读取多个字节的方式。(中等)
 */
public static void method2() throws IOException {
    FileInputStream fis = new FileInputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo33/test.jpg");
    FileOutputStream fos = new FileOutputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo33/copy2.jpg");
 
    byte[] bytes = new byte[1024];
    int len = 0;
    while ((len = fis.read(bytes)) != -1) {
        fos.write(bytes, 0, len);
    }
 
    fis.close();
    fos.close();
}
/**
 * 使用缓冲字节输入输出流(最快)
 */
public static void method3() throws IOException {
    BufferedInputStream bis = new BufferedInputStream(new FileInputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo33/test.jpg"));
    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo33/copy3.jpg"));
 
    byte[] bytes = new byte[1024];
    int len = 0;
    while ((len = bis.read(bytes)) != -1) {
        bos.write(bytes, 0, len);
    }
 
    bos.close();
    bis.close();
}

看自己写的递归的方式完成目录中所有文件及子目录的复制

import java.io.*;
public class Test {
    public static void main(String[] args) {
        try {
            copyDirectory("D:\\用户-常\\Desktop","D:\\用户-常\\Desktop\\新建文件夹\\啊哈哈\\test");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public static void copyFile(File file1,File file2) throws IOException {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file1));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file2));
        byte[] test = new byte[1024];
        for (int read = bis.read(test); read > 0; read--) {
            bos.write(test,0, test.length);
        }
        bos.close();
        bis.close();
    }
    public static void copyDirectory(String Directory1,String Directory2) throws IOException{
        File file1 = new File(Directory1);
        File file2 = new File(Directory2);
        /*if (!file1.exists() || !file1.isDirectory()){
            System.out.println("你要复制的目录不存在或路径不存在");
            return;
        }*/
        if (!file2.exists()){//不存在就多级创建
            file2.mkdirs();
        }
        File[] files = file1.listFiles();
        for (File file : files) {
            if (file.isFile()){
                System.out.println("进来了");
                File file3 = new File(Directory2,file.getName());
                copyFile(file,file3);
            }
            if (file.isDirectory()){
                copyDirectory(file.getAbsolutePath(),file2.getAbsolutePath()+File.separator+file.getName());
            }
        }
    }
}

其他(了解)

处理流之转换流:

InputStreamReader、OutputStreamWriter将字节流和字符流进行转换。 属于处理流的转换流

了解下面代码即可

public static void main(String[] args) throws IOException {
    //使用输入字节流--转换流/FileReader--缓冲字符流
    //将index文件复制到.txt文件里
    FileInputStream fis = new FileInputStream("D:\\用户-常\\Desktop\\index.html");
    InputStreamReader isr = new InputStreamReader(fis);//字符流,没缓冲功能
    BufferedReader br = new BufferedReader(isr);

    FileOutputStream fos = new FileOutputStream("D:\\用户-常\\Desktop\\t.txt");
    OutputStreamWriter osw = new OutputStreamWriter(fos);
    BufferedWriter bw = new BufferedWriter(osw);
    //边读边写
    String s = br.readLine();
    while (s!= null){
        bw.write(s);
        bw.newLine();
        s = br.readLine();
    }
    bw.close();
    osw.close();
    fos.close();
    br.close();
    isr.close();
    fis.close();
}
/*
【转换流】
    目的:将字节流转换成字符流来使用
          输入字节流--转换流---缓冲字符流
     */
处理流之数据流:

DataInputStream、DataOutputStream用来对基本数据类型和字符串进行操作

了解下面代码即可

@Test
public void test() throws IOException {
    //数据流:属于节点流,不能直接跟数据源关联

    //创建数据源
    File file = new File("D:\\用户-常\\Desktop\\t.txt");
    //创建管道流
    FileOutputStream fos = new FileOutputStream(file);
    DataOutputStream dos = new DataOutputStream(fos);
    //使用数据流写入带数据类型的信息
    dos.writeInt(99);
    dos.writeBoolean(false);
    dos.writeDouble(87.5);
    dos.writeUTF("吉林");
    //关闭流
    dos.close();
    fos.close();
}
@Test
public void test1() throws IOException {
    File file = new File("D:\\用户-常\\Desktop\\t.txt");
    FileInputStream fis = new FileInputStream(file);
    DataInputStream dis = new DataInputStream(fis);
    //只能按插入时的顺序读,类型要一样
    System.out.println("刚才写入的整型是:"+dis.readInt());
    System.out.println("刚才写入的布尔是:"+dis.readBoolean());
    System.out.println("刚才写入的小数是:"+dis.readDouble());
    System.out.println("刚才写入的字符串是:"+dis.readUTF());
    //关闭流
    dis.close();
    dis.close();
}
/*
【数据流】存入和取出的信息是带变量类型的,(不能直接跟数据源关联,和字节输入输出流关联)
输送基本数据类型的,在输送的过程中会始终保存信息的变量类型。
     */
处理流之对象流:

ObjectInputStream,ObjectOutputStream用于存储和读取基本数据类型数据或对象的处理流。

它的强大之处就是可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。

序列化和反序列化:

ObjectOutputStream 类 : 把内存中的Java对象转换成平台无关的二进制数据,从而允许把这种二进制数据持久地保存在磁盘上,或通过网络将这种二进制数据传输到另一个网络节点。---->序列化

ObjectInputStream类 : 当其它程序获取了这种二进制数据,就可以恢复成原来的Java对象。---->反序列化

注意:

(1)被序列化的类的内部的所有属性,必须是可序列化的 (基本数据类型都是可序列化的)

(2)transient修饰的属性不会被序列化存储(始终是默认值)。

(3)static修饰的属性只会保存最后传入的值(因为是静态共享资源)。

如果一个类想要实现序列化操作

1.实现序列化Serializable接口

2.添加序列号id,下面是添加序列号id的方法

在这里插入图片描述

了解下面代码即可

@Test
public void test() throws Exception{
    //获取数据源
    File file = new File("D:\\用户-常\\Desktop\\t.txt");
    //创建管道流对象
    FileOutputStream fos = new FileOutputStream(file,true);
    ObjectOutputStream oos = new ObjectOutputStream(fos);
    //写入信息
    Student s1 = new Student(1,"常","男");
    Student s2 = new Student(2,"常哲","男");
    oos.writeObject(s1);//会报没有序列化,Student要实现Serializable标记接口,不用重写
    oos.writeObject(s2);
    //关闭流
    oos.close();
    fos.close();
}
@Test
public void test0() throws Exception{
    File file = new File("D:\\用户-常\\Desktop\\t.txt");
    FileInputStream fis = new FileInputStream(file);
    ObjectInputStream ois = new ObjectInputStream(fis);

    while (fis.available()>0){//要拿输入流的这个方法看还有没有数据
        Object o = ois.readObject();
        if (o instanceof Student){
            Student s = (Student) o;
            System.out.println(s.toString());
        }
    }
    //拿出时Student类的内容变化(例如加了个方法),就会出错
    //需要给一个码:
    /*Student s = (Student) ois.readObject();
    System.out.println(s);
    Student s1 = (Student) ois.readObject();
    System.out.println(s1);*/
    ois.close();
    fis.close();
}
import java.io.Serializable;

/**
 * Serializable是允许当前类对象进行序列化操作
 * 实现了这个接口,没有任何方法需要重写,目的就是标记作用
 * 如果一个类想要实现序列化操作2.实现序列化接口2.添加序列号id
 */
public class Student implements Serializable {
    private static final long serialVersionUID = -5352494921384421054L;
    private int id;
    private String name;
    private String gender;
    public Student(int id, String name, String gender) {
        this.id = id;
        this.name = name;
        this.gender = gender;
    }
    public Student() {
    }
    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 String getGender() {
        return gender;
    }
    public void setGender(String gender) {
        this.gender = gender;
    }
    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", gender=" + gender +
                '}';
    }
}
节点流之打印流(了解)

PrintStream:System.out就是一个PrintStream类型的对象。

System.in : “标准”输入流。—》默认情况下 从键盘输入

System.out : “标准”输出流。 —》默认情况下,输出到控制台。

了解下面代码即可

@Test
public void test() {
    //获得数据源对象,默认控制台
    //创建管道流对象
    PrintStream stream = System.out;//输出流
    stream.println("吉林");
    stream.close();

}
@Test
public void test0() throws IOException {
    InputStream input = System.in;
    int read = input.read();//接收一个数据
    System.out.println("键盘输入了" + (char) read);//结果
    input.close();
}
@Test
public void test1() throws IOException {
    //扫描器
    //        Scanner sc = new Scanner(System.in);//扫描键盘输入的信息
    Scanner sc = new Scanner(new FileInputStream("D:\\用户-常\\Desktop\\记事本.txt"));//扫描D:下的信息
    while (sc.hasNext()){
        System.out.println(sc.next());
    }
    sc.close();
}

面试题(重点)

1. 输入流和输出流联系和区别,节点流和处理流联系和区别(解释+举例子)

​ 首先,你要明白什么是“流”。直观地讲,流就像管道一样,在程序和文件之间,输入输出的方向是针对程序而言,向程序中读入东西,就是输入流,从程序中向外读东西,就是输出流。输入流是得到数据,输出流是输出数据。

​ 而节点流,处理流是流的另一种划分,按照功能不同进行的划分。节点流,可以从或向一个特定的地方(节点)读写数据。处理流是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。如BufferedReader。处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装,称为流的链接。

2. 字符流字节流联系区别;什么时候使用字节流和字符流? (解释+举例子)

​ 字符流和字节流是流的一种划分,按处理照流的数据单位进行的划分。两类都分为输入和输出操作。在字节流中输出数据主要是使用OutputStream完成,输入使的是InputStream,在字符流中输出主要是使用Writer类完成,输入流主要使用Reader类完成。这四个都是抽象类。字符流处理的单元为2个字节的Unicode字符,分别操作字符、字符数组或字符串,而字节流处理单元为1个字节,操作字节和字节数组。字节流是最基本的,所有的InputStrem和OutputStream的子类都是,主要用在处理二进制数据,它是按字节来处理的 但实际中很多的数据是文本,又提出了字符流的概念,它是按虚拟机的编码来处理,也就是要进行字符集的转化 这两个之间通过 InputStreamReader,OutputStreamWriter来关联,实际上是通过byte[]和String来关联的。

面试题二(重点)

1. 列举常用字节输入流和输出流并说明其特点,至少5对。

FileInputStream 从文件系统中的某个文件中获得输入字节。

ByteArrayInputStream 包含一个内部缓冲区,该缓冲区包含从流中读取的字节。内部计数器跟踪 read 方法要提供的下一个字节。

FilterInputStream 包含其他一些输入流,它将这些流用作其基本数据源,它可以直接传输数据或提供一些额外的功能。FilterInputStream 类本身只是简单地重写那些将所有请求传递给所包含输入流的 InputStream 的所有方法。FilterInputStream 的子类可进一步重写这些方法中的一些方法,并且还可以提供一些额外的方法和字段。

ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。

ObjectOutputStream 和 ObjectInputStream 分别与 FileOutputStream 和 FileInputStream 一起使用时,可以为应用程序提供对对象图形的持久存储。ObjectInputStream 用于恢复那些以前序列化的对象。其他用途包括使用套接字流在主机之间传递对象,或者用于编组和解组远程通信系统中的实参和形参。

StringBufferInputStream此类允许应用程序创建输入流,在该流中读取的字节由字符串内容提供。应用程序还可以使用ByteArrayInputStream 从 byte 数组中读取字节。 只有字符串中每个字符的低八位可以由此类使用。

ByteArrayOutputStream此类实现了一个输出流,其中的数据被写入一个 byte 数组。缓冲区会随着数据的不断写入而自动增长。可使用 toByteArray() 和 toString() 获取数据。

FileOutputStream文件输出流是用于将数据写入 File 或 FileDescriptor 的输出流。文件是否可用或能否可以被创建取决于基础平台。特别是某些平台一次只允许一个 FileOutputStream(或其他文件写入对象)打开文件进行写入。在这种情况下,如果所涉及的文件已经打开,则此类中的构造方法将失败。

FilterOutputStream类是过滤输出流的所有类的超类。这些流位于已存在的输出流(基础 输出流)之上,它们将已存在的输出流作为其基本数据接收器,但可能直接传输数据或提供一些额外的功能。 FilterOutputStream 类本身只是简单地重写那些将所有请求传递给所包含输出流的 OutputStream 的所有方法。FilterOutputStream 的子类可进一步地重写这些方法中的一些方法,并且还可以提供一些额外的方法和字段。

ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。可以使用 ObjectInputStream 读取(重构)对象。通过在流中使用文件可以实现对象的持久存储。如果流是网络套接字流,则可以在另一台主机上或另一个进程中重构对象。

PipedOutputStream可以将管道输出流连接到管道输入流来创建通信管道。管道输出流是管道的发送端。通常,数据由某个线程写入 PipedOutputStream 对象,并由其他线程从连接的 PipedInputStream 读取。不建议对这两个对象尝试使用单个线程,因为这样可能会造成该线程死锁。如果某个线程正从连接的管道输入流中读取数据字节,但该线程不再处于活动状态,则该管道被视为处于毁坏状态。

2. 说明缓冲流的优点和原理(重点)Buffer

不带缓冲的流的工作原理:它读取到一个字节/字符,就向用户指定的路径写出去,读一个写一个,所以就慢了。带缓冲的流的工作原理:读取到一个字节/字符,先不输出,等凑足了缓冲的最大容量后一次性写出去,从而提高了工作效率

优点:减少对硬盘的读取次数,降低对硬盘的损耗。

3. 序列化的定义、实现和注意事项(重点)

想把一个对象写在硬盘上或者网络上,对其进行序列化,把他序列化成为一个字节流。

实现和注意事项:

  1. 实现接口Serializable Serializable接口中没有任何的方法,实现该接口的类不需要实现额外的方法。
  2. 如果对象中的某个属性是对象类型,必须也实现Serializable接口才可以
  3. 序列化对静态变量无效
  4. 如果不希望某个属性参与序列化,不是将其static,而是transient
  5. 串行化保存的只是变量的值,对于变量的任何修饰符,都不能保存
  6. 序列化版本不兼容
4. 使用IO流完成文件夹复制(结合递归)
import java.io.*;
/*
 * CopyDocJob定义了实际执行的任务,即
 * 从源目录拷贝文件到目标目录
*/
public class CopyDir2 {
	public static void main(String[] args) {
		try {
			copyDirectiory("d:/301sxt","d:/301sxt2");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	/*
	 * 复制单个文件
	 * @param sourceFile 源文件
	 * @param targetFile 目标文件
	 * @throws IOException
	 */
    private static void copyFile(File sourceFile, File targetFile) throws IOException {
        BufferedInputStream inBuff = null;
        BufferedOutputStream outBuff = null;
        try {
            // 新建文件输入流
            inBuff = new BufferedInputStream(new FileInputStream(sourceFile));
            // 新建文件输出流
            outBuff = new BufferedOutputStream(new FileOutputStream(targetFile));
            // 缓冲数组
            byte[] b = new byte[1024 * 5];
            int len;
            while ((len = inBuff.read(b)) != -1) {
                outBuff.write(b, 0, len);
            }
            // 刷新此缓冲的输出流
            outBuff.flush();
        } finally {
            // 关闭流
            if (inBuff != null)
                inBuff.close();
            if (outBuff != null)
                outBuff.close();
        }
    }
    /*
     * 复制目录
     * @param sourceDir 源目录
     * @param targetDir 目标目录
     * @throws IOException
     */
    private static void copyDirectiory(String sourceDir, String targetDir) throws IOException {
        // 检查源目录
    	File fSourceDir = new File(sourceDir);
    	if(!fSourceDir.exists() || !fSourceDir.isDirectory()){
    		return;
    	}    	
    	//检查目标目录,如不存在则创建
    	File fTargetDir = new File(targetDir);
    	if(!fTargetDir.exists()){
    		fTargetDir.mkdirs();
    	}    		
        // 遍历源目录下的文件或目录
        File[] file = fSourceDir.listFiles();
        for (int i = 0; i < file.length; i++) {
            if (file[i].isFile()) {
                // 源文件
                File sourceFile = file[i];
                // 目标文件
                File targetFile = new File(fTargetDir, file[i].getName());
                copyFile(sourceFile, targetFile);
            }            
            //递归复制子目录
            if (file[i].isDirectory()) {
                // 准备复制的源文件夹
                String subSourceDir = sourceDir + File.separator + file[i].getName();
                // 准备复制的目标文件夹
                String subTargetDir = targetDir + File.separator + file[i].getName();
                // 复制子目录
                copyDirectiory(subSourceDir, subTargetDir);
            }
        }
    }
}
  • 54
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值