java基础之IO流

IO流

File类

File 文件和目录(文件夹)路径名的抽象表示。

构造方法

File(String pathname);//参数就是指定的路径/如果没有指定路径(默认是在当前项目下)
通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例
File(File parent, String child);//从父抽象路径名和子路径名字符串创建新的 File实例。
File(String parent, String child);//参数1:父目录地址    参数2:具体的子文件地址

成员方法

创建/删除/重名
public boolean createNewFile()   throws IOException :表示创建文件 :如果不存在,则创建
public boolean mkdir():创建文件夹,如果不存在,则创建;否则就返回false
public boolean mkdirs():创建多个文件,如果父目录不存在,则创建
public boolean delete():删除文件或者文件夹(如果删除文件夹,文件夹必须为空目录)
public boolean renameTo(File dest):重命名
参数传递的修改的File对象
判断功能
public boolean canRead()是否可读
public boolean canWrite()是否可写
public boolean exists():是否存在
public boolean isFile():是否是文件
public boolean isDirectory():是否是文件夹
public boolean isHidden():是否隐藏
高级获取功能
public long length()
public String getName():获取抽象路径 名所表示的文件或者目录的名称
public File[] listFiles():获取某个目录下的所有的文件以及文件夹的File数组
public String[] list():获取某个抽象路径名所表示的文件以及目录的字符串数组

需求:获取
D盘下的所有的文件夹以及文件的名称…

public class FileDemo2 {
    public static void main(String[] args) {

        //创建File对象,描述当前项目下的aaa.txt文件
        File file = new File("aaa.txt") ;
        System.out.println(file.canRead());
        System.out.println(file.canWrite());
        System.out.println(file.exists());
        System.out.println(file.isDirectory());//false
        System.out.println(file.isFile());
        System.out.println(file.isHidden());
        System.out.println(file.length());
        System.out.println(file.getName());
        System.out.println("------------------------");

        // public File[] listFiles():获取某个目录下的所有的文件以及文件夹的File数组
        //描述D盘
        File file2 = new File("d://") ;
        File[] fileArray = file2.listFiles();
        //防止空指针异常
        if(fileArray!=null){
            for(File f :fileArray){
                System.out.println(f.getName());
            }
        }
        System.out.println("----------------------------------");
        //public String[] list():获取某个抽象路径名所表示的文件以及目录的字符串数组
        String[] strArray = file2.list();
        if(strArray!=null){
            for(String s:strArray){
                System.out.println(s);
            }
        }


    }
}
eg.1
需求:
将D:\EE_2106\day25\code路径下logo.jpg---->改名为  D:\EE_2106\day25\code路径下 mv.jpg
如果两个地址一样:只是改名
如果地址不一样,剪切并改名!
public class FileDemo {
    public static void main(String[] args) throws IOException {
        //表示:E盘下的demo文件夹中的a.txt文件
        //File(String pathname) 方式1 (推荐)
       // File file = new File("e://demo//a.txt") ;只是表示这个路径,如果创建a.txt文件,系统找不到指定路径

        File file = new File("D:\\EE_2106\\day25\\code\\a.txt"); //绝对路径
        File file2 = new File("aaa.txt");//没有带路径,就默认在当前项目下(相对路径)
        File file3 = new File("D:\\EE_2106\\day25\\code\\demo") ;
        File file4 = new File("aaa\\bbb\\ccc\\ddd") ;

        //File(File parent, String child) 方式2
      /*  File file2 = new File("E://demo") ;
        File file3 = new File(file2,"a.txt") ;

        //File(String parent, String child):方式3
        File file4 = new File("E://demo","a.txt") ;*/
       // public boolean createNewFile()
        System.out.println(file.createNewFile());
        System.out.println(file2.createNewFile());
        System.out.println(file3.mkdir());
        System.out.println(file4.mkdirs());
        System.out.println(file3.delete());
        System.out.println(file.delete());
        System.out.println("------------------------");
        //D:\EE_2106\day25\code路径下logo.jpg :描述下这个地址File
       // File srcFile  = new File("D:\\EE_2106\\day25\\code\\logo.jpg") ;
        File srcFile = new File("D:\\EE_2106\\day25\\code\\mv.jpg") ;
        File destFile = new File("高圆圆.jpg") ;//当前项目路径下了
        System.out.println(srcFile.renameTo(destFile)) ;



    }
}

eg.2
需求2:
获取D盘下所有的以.jpg结尾的文件

分析:

1)描述下D盘

  1. public File[] listFiles():获取D盘下的所有的文件以及文件夹的File数组
    2.1)对获取到的数组进行非判断,如果不为null,再去判断
    2.2)判断File是一个文件
    2.3)判断:文件必须以.jpg结尾。String类 endsWith(".jpg")

提供了另一个重载功能

public File[] listFiles(FilenameFilter filter)
String[] list(FilenameFilter filter)
//参数为:文件名称过滤器FilenameFilter:接口

成员方法

boolean accept(File dir,String name);//测试指定文件是否包含在文件列表中
返回如果true,将文件添加到文件列表中

1)描述下D盘

2)public File[] listFiles(FilenameFilter filenamefilter):

获取D盘下的File数组的时候,就已经指定文件进行过滤…

import java.io.File;
import java.io.FilenameFilter;

public class IOtest01 {

    public static void main(String[] args) {

        File file = new File("e://");

        File[] files1 = file.listFiles();

        //方法一:
        if (files1 != null) {
            for (File f : files1) {
                if (f.isFile()) {
                    if (f.getName().endsWith(".txt")) {
                        System.out.println(f);
                    }
                }
            }
        }

        System.out.println("————————————————");

        //方法二:
        File srcfile = new File("e://");

        //获取当前D盘下的所有文件以及文件夹File数组,并进行文件名过滤
        //public File[] listFiles(FilenameFilter filter)
        File[] files2 = srcfile.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                //返回true:表示将指定文件添加列表文件中
                //描述文件所表示抽象路径File
                File file1 = new File(dir, name);

                //两个条件:file是文件并且file的文件名称以".jpg结尾"
                return file1.isFile() && file1.getName().endsWith(".txt");
            }
        });

        if (files2 != null) {
            for (File f : files2) {
                System.out.println(f.getName());
            }
        }
    }
}

递归

方法递归

方法调用方法本身的一种现象,并非是方法嵌套方法

前提条件

1)必须有一个成员方法

2)必须有方法递归的出口条件(结束条件),如果没有出口条件,就是死递归…

3)还存在一定的规律

注意事项

构造方法不存在递归

eg.1 5的阶乘

public class DiGuiDemo {

   public static void main(String[] args) {
       System.out.println("5的阶乘是:"+jieCheng(5));
   }

    //递归:需要考虑(一定要有规律)
    private static int jieCheng(int i) {
       if(i==1){
           return 1 ;
       }else{
           return i * jieCheng(i-1) ;
       }
    }

}

eg.2 需求:使用递归方式去删除D盘某个demo文件夹中有很多个目录。

public class DiGuiTest {
    public static void main(String[] args) {

         //描述D盘的demo文件夹
         File srcFloder = new File("d://demo") ;//想删的文件夹地址
         //调用递归删除的方法
        deleteFloder(srcFloder) ;
    }
    
    public static void deleteFloder(File srcFloder) {
        //获取srcFloder下的所有的文件以及文件的File数组
        File[] fileArray = srcFloder.listFiles();
        if(fileArray!=null){
            for(File file:fileArray){
                //获取到每一个file对象
                //如果file是文件夹,继续回到deleteFloder(srcFloder) ; 删除文件夹
                if(file.isDirectory()){
                    deleteFloder(file) ;
                }else{
                    //判断是文件,必须以.java结尾 文件
                    if(file.getName().endsWith(".java")){
                        //删除的同时----获取名称
                        System.out.println(file.getName()+"------------"+file.delete());
                    }
                }

            }
            //删除文件夹
            System.out.println(srcFloder.getName()+"----"+srcFloder.delete());
        }
    }
}

InputStream&OutputStream

IO流的分类

按流的方向

输入和输出流

按类型分

字节和字符流:字节先出现,后面在有字符流

再次流的方向划分

字节输入流:InputStream:表示输入字节流的所有类的超类(父类)

字节输出流:OutputStream:表示字节输出流的所有类的超类

字符输入流:Reader表示输入字符流的抽象类

字符输出流:Writer表示输出字符流的抽象类

字节/字符流都很多子类

XXXInputStream

XXXOutputStream

XXXReader

XXXWriter

字节输出流

OutputStream抽象类

子类进行实例化FileOutputStream:将指定的内容写到文件中

实现步骤:

1)创建文件输出流对象 :

FileOutputStream(String name) :推荐:可以指定参数地址
FileOutputStream(File file)

2)写数据

public void write(int b) throws IOException 写一个字节
public void write(byte[] bytes) throws IOException 写一个字节数组
public void write(byte[] bytes,int off,int len) throws IOException:写一部分字节数组

​ 3)关闭资源

public class FileOutputStreamDemo {
    public static void main(String[] args) throws IOException {
        
        //创建文件输出流对象
        //指向某个盘符下的文件中(或者当前项目下)
        FileOutputStream fos = new FileOutputStream("my.txt");//文件需要被创建当前项目下

        //2)写数据
        for (int x = 0; x < 10; x++) {
            fos.write(("hello" + x).getBytes());

            //windows操作系统  "\r\n"代表换换行
            fos.write("\r\n".getBytes());
        }

        //3)关闭资源
        fos.close(); //释放fos流对象所指向的my.txt的系统资源

    }
}

在字节输出流中加入异常处理(捕获异常)

public class FileOutputStreamDemo2 {

    public static void main(String[] args) {

       // method1() ;
        method2() ;//
    }

    //标准方式:try...catch...finally
    //统一处理
    private static void method2() {
        FileOutputStream fos = null ;
        //alt+ctrl+t--->
        try {
           fos = new FileOutputStream("fos2.txt") ;
            //写数据
            fos.write("hello,我来了".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //释放资源

                if(fos!=null){
                    try {
                        fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

        }
    }

    //分别try...catch...(不用,这种方式阅读性很差)
    private static void method1() {
        //在当前项目下输出fos.txt
        //创建字节输出流对象
        FileOutputStream fos = null ;
        try {
             fos = new FileOutputStream("fos.txt") ;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        //写数据
        try {
            fos.write("hello,IO".getBytes()) ;
        } catch (IOException e) {
            e.printStackTrace();
        }

        //关闭资源
        try {
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

流的拷贝

字节输入流:InputStream
子类:FileInputStream

实现步骤:
	需要读取当前项目下的fis.txt文件
	1)创建文件字节输入流对象,指向 fis.txt
		public FileInputStream(String name) throws FileNotFoundException
	2)读内容
		read(byte[] bytes):一次读取一个字节数组
		read():一次读取一个字节
	3)释放资源

	读取文件的时候,一次读取一个字节,存在中文乱码, 在最终输出的结果 (char)by   (场景:将某一个文件内容打印在控制台上了)

	"abc" 英文 读一个字节  a--->97   b --98
	针对中文字符: 现在idea环境: 编码格式:utf-8格式: 一个中文对应三个字节 ,和前面的英文拼接出现问题,只要中文都会乱码
	
	因此才出现了字符流(加入编码和解码的格式)
public class FileInputStreamDemo {
    public static void main(String[] args) {
        //创建一个字节输入流对象
        FileInputStream fis = null ;
        try {
          // fis  = new FileInputStream("fis.txt") ;
           fis  = new FileInputStream("DiGuiTest.java") ; //读取当前项目下的DiGuiTest.java
            //读取内容
          /*  //第一次读取
            int by = fis.read(); //字节数
            System.out.println(by);
            System.out.println((char)by); //获取的字符
            //第二次读取
            by  = fis.read();
            System.out.println((char)by);
            //第三次读取
            by = fis.read() ;
            System.out.println((char)by);
            //第四次读取
            by = fis.read() ;
            System.out.println(by);//字节数
            System.out.println((char)by);*/
          //使用循环优化:  结束条件:获取的字节数为-1

            //当前不知道循环多少次:while循环
           //将判断,赋值一块去使用 (模板代码)
           int by = 0 ; //字节数为0
           while((by=fis.read())!=-1) {
               System.out.print((char)by);
           }


        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //释放资源
            if(fis!=null){
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}

读写复制操作:一次读取一个字节的方式
一次读取一个字节数组

需求:

将当前项目下的DiGuiTest.java 的内容 复制到D盘下的Copy.java文件中

分析:

源文件: 当前项目下 “DiGuiTest.java”

封装源文件:FileInputStraem(String pathname)一次读取一个字节

目的地文件: D://Copy.java

封装目的地文件:FileOutputStream(String pathname)一次写一个字节

public class CopyFileDemo {
    public static void main(String[] args) {

        long start = System.currentTimeMillis() ;//时间毫秒值

       // method("DiGuiTest.java","D://Copy.java") ;
        method2("DiGuiTest.java","D://Copy.java") ;

        long end  = System.currentTimeMillis() ;
        System.out.println("共耗时:"+(end-start)+"毫秒");
    }

    private static void method2(String srcFile, String destFile) {
        FileInputStream fis  = null ;
        FileOutputStream fos = null ;
        try {
            //  封装源文件:FileInputStraem(String pathname)
            //字节输入流
            fis = new FileInputStream(srcFile) ;
            //字节输出流
            // 封装目的地文件:FileOutputStream(String pathname)
            fos = new FileOutputStream(destFile) ;

            //读写复制操作
            //一次读取一个字节数组
            byte[] bytes = new byte[1024] ;
            int len = 0 ;
            while((len=fis.read(bytes))!=-1){
                //赋值
                //fos流对象中写
                //带上len的使用
                fos.write(bytes,0,len);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }finally {

            try {
                fos.close();
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 一次读取一个字节:读写复制
     * @param srcFile  源文件
     * @param destFile 目的地文件
     */
    private static void method(String srcFile, String destFile) {
        FileInputStream fis  = null ;
        FileOutputStream fos = null ;
        try {
            //  封装源文件:FileInputStraem(String pathname)
            //字节输入流
            fis = new FileInputStream(srcFile) ;
            //字节输出流
            // 封装目的地文件:FileOutputStream(String pathname)
            fos = new FileOutputStream(destFile) ;

            //读写复制操作
            //一次读取一个字节
            int by = 0 ;
            while((by=fis.read())!=-1){
                //没有读完,继续复制 :写一个字节
                fos.write(by);

            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {

            try {
                fos.close();
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
public int read(byte[] b)throws IOException//一次读取一个字节数组,返回值值的是每次读取的实际字节数
需求:将fis2.txt读取出来,并展示在控制台上
public class FileInputStreamDemo2 {
    public static void main(String[] args) {
        //创建字节输入流对象
        FileInputStream fis = null ;
        try {
            fis = new FileInputStream("fis2.txt") ;

         //创建一个数组:长度:1024或者1024的整数倍
          byte[] buffer = new byte[1024] ;   //长度虽然1024个长度
          int len = 0 ;
          while((len=fis.read(buffer))!=-1){
              //每次获取的从0开始获取实际字节长度
              System.out.println(new String(buffer,0,len)) ;
          }

        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

字节流

字符流和字节流读取文件的方式

import java.io.*;

public class BufferedTest {

    public static void main(String[] args) {

        long start = System.currentTimeMillis();

		Copy1("srcFile","destFile");
        Copy2("srcFile","destFile");
        Copy3("srcFile","destFile");
        Copy4("srcFile","destFile");

        long end = System.currentTimeMillis();

        System.out.println("本次共运行了"+(end-start)+"毫秒");

    }

    //基本的字节流一次读取一个字节
    public static void Copy1(String srcFile,String destFile)throws IOException{

        FileInputStream fis = null;
        FileOutputStream fos = null;

        fis = new FileInputStream(srcFile);
        fos = new FileOutputStream(destFile);

        int by = 0;
        while((by=fis.read())!=-1){
            fos.write(by);
        }

        fos.close();
        fis.close();

    }

    //基本的字节流一次读取一个字节数组
    public static void Copy2(String srcFile,String destFile)throws IOException{

        FileInputStream fis = null;
        FileOutputStream fos = null;

        fis = new FileInputStream(srcFile);
        fos = new FileOutputStream(destFile);

        byte[] bytes = new byte[1024];
        int len = 0;
        while((len=fis.read(bytes))!=-1){
            fos.write(bytes,0,len);
        }

        fos.close();
        fis.close();

    }

    //缓冲流一次读取一个字节
    public static void Copy3(String srcFile,String destFile)throws IOException{

        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;

        bis = new BufferedInputStream(new FileInputStream(srcFile));
        bos = new BufferedOutputStream(new FileOutputStream(destFile));

        int by = 0;
        while((by=bis.read())!=-1){
            bos.write(by);
        }

        bos.close();
        bis.close();

    }

    //缓冲流一次读取一个字节数组
    public static void Copy4(String srcFile,String destFile)throws IOException{

        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;

        bis = new BufferedInputStream(new FileInputStream(srcFile));
        bos = new BufferedOutputStream(new FileOutputStream(destFile));

        byte[] bytes = new byte[1024];
        int len = 0;
        while((len=bis.read(bytes))!=-1){
            bos.write(bytes,0,len);
        }

        bos.close();
        bis.close();

    }

}

字符流

Reader/Writer子类:转换流

InputStreamReader(InputStream in);
OutputStreamWriter(OutputStream out);

//他们不能直接去操作文件,jdk提供了这两种类型的便捷类,可以直接操作文件
FileReader(File file);
FileReader(String pathname);

FileWriter(File file);
FileWriter(String filename);

//这两个类:使用的平台的默认编码和解码 (utf-8)
Reader:抽象类

具体的子类:字符转换输入流 InputStreamReader

构造方法
InputStreamReader(InputStream in) ;//使用平台默认解码集进行读
InputStreamReader(InputStream in,String charset) ;//使用指定的解码集进行读

字符流的出现是在字节流的后面,可以解决中文乱码问题

Writer:抽象类

提供子类:字符转换输出流: 字节输出流通向字符输出流的桥梁!

构造方法
OutputStreamWriter(OutputStream out) ;//使用平台默认编码集写入数据
OutputStreamWriter(OutputStream out, String charsetName) ;//使用指定的字符集进行编码 写入数据
import java.io.*;

public class Reader_WriterTest01 {

    public static void main(String[] args) throws IOException {

        InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\IO操作\\c.txt"));
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:\\IO\\c3.txt"));

        char[] chars = new char[1024];
        int len = 0;
        while((len = isr.read(chars))!=-1){
            osw.write(chars,0,len);
            System.out.println(new String(chars,0,len));
            osw.flush();
        }

        osw.close();
        isr.close();

    }

}
asdasdas
asdasd
sfdsdg
adas
as11223
aassa
asda
s2121
public class Reader_WriterTest02 {
    public static void main(String[] args) throws IOException {

        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:\\千锋\\IO\\c4.txt"));

        String s = "12345643213224";
        char[] chars =s.toCharArray();

        osw.write(chars);
        osw.flush();

        osw.close();

    }
}
BufferedReaer/BufferedWriter  :读写复制操作
	一次读取一个字符
	一次读取一个字符数组

特有功能
	利用BufferedReader的readLine()读取一行
	利用BufferedWriter写一行,然后换行

一个文本文件读写复制:
阻塞流 (传统的IO流)
    当一个线程如果操作的是读的动作,read(byte[] byte/char[] ..)/readLine():都属于阻塞式方法
    另一个线程如果操作的是写的动作,读的线程如果开始读,这边写的线程才能开始进行写的复制操作!

基本的字节流:一次读取一个字节/一次读取一个字节数组
字节缓冲流:一次读取一个字节/一次读取一个字节数组

字符转换流:
    InputStreamReader(InputStream in)
    OutputStreamWriter(OutputStream out)
    一次读取一个字符/一次读取一个字符数组

转换流的便捷类
    FileReader(String name)
    FileWriter(String writer)
    一次读取一个字符/一次读取一个字符数组

    BufferedReader
    BufferedWriter
    一次读取一个字符/一次读取一个字符数组
特有功能:
    一次读取一行内容


BufferedReader:字符缓冲输入流

BufferedReader键盘录入数据
Scanner(InputSteram in)、String nextLine()
BufferedReader(Reader in);

InputStreamReader(InputStream in);//转换流

如果直接进行读的操作(直接操作文件)FileReader(String pathName)

创建使用默认大小的输入缓冲区的缓冲字符输入流。

BufferedReader(Reader in, int size):指定缓冲区大小

特有功能:

public String readLine() :一次读取一行内容

BufferedWriter:字符缓冲输出流

BufferedWriter(Writer out) :创建默认的缓冲区大小: 默认大小:defaultcharbuffersize:8192(默认值足够大)

BufferedWriter(Writer out, int sz) :指定的大小

public void newLine() throws IOException:写入行的分隔符号

BufferedReaer/BufferedWriter :读写复制操作
一次读取一个字符
一次读取一个字符数组

特有功能:

利用BufferedReader的readLine()读取一行
利用BufferedWriter写一行,然后换行

eg.将当前项目下的ReaderDemo.java复制到当前项目下:copy.java

import java.io.*;

//一次读取一行
public class Reader_WriterTest03 {

    public static void main(String[] args) throws IOException {
        BufferedReader br = null;
        BufferedWriter bw = null;

        br = new BufferedReader(new FileReader("D:\\IO操作\\c.txt"));
        bw = new BufferedWriter(new FileWriter("D:\\IO\\c5.txt"));

        String line = null;
        while((line = br.readLine())!=null){
            bw.write(line);
            bw.newLine();
            bw.flush();
        }

        bw.close();
        br.close();

    }

}

合并流

SequenceInputStream:

构造方法
public SequenceInputStream(InputStream s1,InputStream s2)//参数1和参数2:分别要读取的字节输入流对象
public SequenceInputStream(Enumeration<? extends InputStream> e) ;//将两个以上的文件进行读取
Vector<InputStream>add//(添加多个字节输入流对象)
eg.
public class SequenceTest {

    public static void main(String[] args) throws IOException{

        InputStream isr1 = new FileInputStream("D:\\IO\\c1.txt");
        InputStream isr2 = new FileInputStream("D:\\IO\\c2.txt");
        InputStream isr3 = new FileInputStream("D:\\IO\\c3.txt");
        InputStream isr4 = new FileInputStream("D:\\IO\\c4.txt");
        InputStream isr5 = new FileInputStream("D:\\IO\\c5.txt");

        Vector<InputStream> vector = new Vector();


        vector.add(isr1);
        vector.add(isr2);
        vector.add(isr3);
        vector.add(isr4);
        vector.add(isr5);

        //public Enumeration<E> elements() ---- >类似于Collection的Iterator迭代器
        Enumeration<InputStream> enumeration = vector.elements();

        //创建合并流对象  封装源文件
        SequenceInputStream sis = new SequenceInputStream(enumeration);

        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\IO\\c.txt"));

        int b = 0;
        while((b = sis.read())!=-1){
            bos.write(b);
            bos.flush();
        }

        bos.close();
        sis.close();

    }

}

序列化&反序列化

序列化

ObjectOutputStream

将某个实体对象写入到流对象中---->将一个对象变成流数据

构造方法

protected ObjectOutputStream()
protected ObjectOutputStream(OutputStream out) :将某个对象通过底层的基本字节输出进行写的动作
public final void writeObject(Object obj) throws IOException

反序列化

ObjectInputStream

将流数据----还原成 “对象”

构造方法

public ObjectInputStream(InputStream in)
public final Object readObject()
throws IOException, ClassNotFoundException

java.io.NotSerializableException: com.qf.serailizable_05.Person

NotSerializableException:未实现序列化接口的异常
一个类在进行序列化的时候,(将类的对象写入序列化流中),标记接口Serializable 它有个特点为当前这个Person进行编码(为类以及类的成员----->序列化化版本ID(签名):SerialversonUID)

java.io.InvalidClassException: com.qf.serailizable_05.Person; local class incompatible:stream classdesc serialVersionUID = 2588921225545403990,local class serialVersionUID = -862808041229244683

在进行序列化的时候:当前的serialVersionUID:序列化版本id号 (假设100):内存中生成一个id值
在进行反序列化的时候:将流指向对象:Person类的字段信息更改了(类的签名信息就会被更改),那么直接进行反序列化产生的serialVersionUID=(假设200)
两个序列ID不一样
序列化版本id保证,在idea中生成一个固定的序列版本id号 (一般都针对实体类)

一个实体类:

​ 1)当前类必须为具体类 class 类名{}

​ 2)必须存在私有字段(私有成员变量)

​ 3)必须提供公共的setXXX()/getXXX()

​ 4)如果当前类需要在网络中进行传输(分布式系统中)必须implements Serializable

idea—>file—>setting---->editor---->Inspections----->java---->序列化serializion issue—>serializable class 打上对钩即可!

需求:将Person p = new Person(“高圆圆”,42) ;---->变成流对象 进行传输

import java.io.Serializable;

public class Person implements Serializable {

    //产生一个固定的序列化版本Id
    private static final long serialVersionUID = 8988325735017562383L; //常量值

    String name;
    int age; //transient:想让某个字段不参与序列化:这个字段(成员变量就使用transient)

    public Person() {
    }

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

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
import java.io.*;

public class Test {
    public static void main(String[] args) throws IOException, ClassNotFoundException {

        myWriter();

        myReader();

    }

    //序列化
    public static void myWriter() throws IOException {
        //创建Person对象
        Person person = new Person("老大", 12);

        //protected ObjectOutputStream(OutputStream out):创建一个序列化流对象
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\IO操作\\a.txt"));

        //将p对象写入到oos流对象中
        //public final void writeObject(Object obj)throws IOException
        oos.writeObject(person);

        //释放资源
        oos.close();
    }

    //反序列化
    public static void myReader() throws IOException, ClassNotFoundException {
        //创建反序列化流对象
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\IO操作\\a.txt"));

        //读
        //public final Object readObject()
        Object o = ois.readObject();

        //关闭流
        ois.close();
        System.out.println(o);
    }

}
Person{name='老大', age=12}

Properties

概念

Properties extends Hashtable<K,V> ,它没有泛型,Key和Value都是String

表示一组持久的属性。 Properties可以保存到流中或从流中加载。

属性列表中的每个键及其对应的值都是一个字符串。

1)可以使用Map的功能

put(K ,V)
遍历:keySet()通用

2)有自己特有功能添加元素和遍历

public Object setProperty(String key,String value):给属性列表中添加属性描述(key和value)
public Set<String> stringPropertyNames():获取属性列表中的所有的键
public String getProperty(String key):在属性列表中通过键获取值

Propeties:键和值都是字符串类型:可能需要在src(类所在的路径:类路径)

作为一个配置文件

将字节输入流或者字符输入中所在的文件中的内容加载属性列表中

void load(Reader reader)
void load(InputSteram in)

将Properties里面存储的内容,保存到某个目录的xxx配置文件中保存

public void store(Writer writer,String comments)
public void store(OutputStream out,String comments)

将属性列表中的内容保存到指定字节输出流/字符输出流所指向那个文件中

eg.1

import java.util.Properties;
import java.util.Set;

public class PropertiesTest01 {
    public static void main(String[] args) {
        //Properties() :空参构造
        Properties properties = new Properties();

        // System.out.println(properties);
        //利用Map集合的功能去添加元素
        properties.put("高圆圆", "赵又廷");
        properties.put("文章", "姚笛");
        properties.put("文章", "马伊琍");
        properties.put("王宝强", "马蓉");
        // System.out.println(properties);

        //遍历
        Set<Object> keySet = properties.keySet();
        for (Object key : keySet) {
            //通过key获取value
            Object value = properties.get(key);
            System.out.println(key + "---" + value);
        }

        System.out.println("---------------------------------------");

        //创建一个空的属性列表
        Properties prop = new Properties();
        prop.setProperty("张三", "30");
        prop.setProperty("李四", "40");
        prop.setProperty("王五", "35");
        prop.setProperty("赵六", "45");


        //遍历:
        Set<String> set = prop.stringPropertyNames();//获取所有键
        for (String key : set) {
            String value = prop.getProperty(key);
            System.out.println(key + "---" + value);

        }

    }
}
高圆圆---赵又廷
王宝强---马蓉
文章---马伊琍
---------------------------------------
赵六---45
王五---35
张三---30
李四---40

eg.2

import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.Set;

public class PropertiesTest02 {
    public static void main(String[] args) throws IOException{

        myStore();

        myLoad();

    }

    //将属性集合类中的内容--保存到指定文件汇中
    public static void myStore()throws IOException{
        Properties prop = new Properties();

        //添加key和value
        prop.setProperty("张三丰","56");
        prop.setProperty("吴奇隆","60");
        prop.setProperty("成龙","65");
        prop.setProperty("刘德华","70");

        //public void store(Writer writer,String comments):
        //参数2:给当前属性列表中加入一个描述
        //保存指定的文件中
        prop.store(new FileWriter("D:\\IO操作\\d.txt"),"text01");

        System.out.println("保存完毕!");
    }

    //加载:需要将names.txt文件加载到属性列表中
    public static void myLoad()throws IOException{
        //创建一个空的属性列表
        Properties prop = new Properties();
        System.out.println(prop);

        //读取src路径下的names.properties
        //1.获取当前类所在的字节码文件对象
        Class clazz = PropertiesTest02.class;

        //2.获取当前类所在的类加载器Class:public ClassLoader getClassLoader()
        ClassLoader classLoader = clazz.getClassLoader();

        //3.在类加载器中,获取当前资源文件(配置文件names.proprites)所在的输入流对象
        //public InputStream getResourceAsStream(String name)
        //text01.properties必须在src目录下
        InputStream ism = classLoader.getResourceAsStream("text01.properties");
        
        //将inputStream加载到属性集合类中 void load(InputStream in)
        prop.load(ism);

        System.out.println(prop);
        
        //遍历
        Set<String> set = prop.stringPropertyNames();
        for(String s: set){
            String value = prop.getProperty(s);
            System.out.println(s+"--"+value);
        }

    }

}
保存完毕!
{}
{liso=70, zhangsan=65, liuwu=56, dada=60}
liso--70
zhangsan--65
liuwu--56
dada--60

IO流总结

I0流原理及流的分类

Java IO流原理

​ 1.I/O是Input/Output的缩写,I/O技术是非常实用的技术, 用于处理数据传输。如读/写文件,网络通讯等。

​ 2.Java程序中, 对于数据的输入/输出操作以"流(stream)”的方式进行。

​ 3.java.io包 下提供了各种"流”类和接口,用以获取不同种类的数据,并通过方法输入或输出数据。

​ 4.输入input:读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中。

​ 5.输出output:将程序(内存)数据输出到磁盘、光盘等存储设备中。

流的分类

​ 按操作数据单位不同分为:字节流(8 bit)二进制文件,字符流(按字符)文本文件

​ 按数据流的流向不同分为:输入流,输出流

​ 按流的角色的不同分为:节点流,处理流/包装流

抽象基类字节流字符流
输入流InputStreamReader
输出流OutputStreamWriter

FileReader 和FileWriter介绍

​ FileReader和FileWriter是字符流,即按照字符来操作io

FileReader相关方法:

​ 1) new FileReader(File/String)

​ 2) read:每次读取单个字符,返回该字符,如果到文件末尾返回-1

​ 3) read(char[]):批量读取多个字符到数组,返回读取到的字符数,如果到文件末尾返回-1

​ 相关API:

​ 1) new String(char[):将char[]转换成String

​ 2) new String(charD.off,len):将char[]的指定部分转换成String

FileWriter常用方法

​ 1) new FileWriter(File/String):覆盖模式,相当于流的指针在首端

​ 2) new FileWriter(File/String.true):追加模式,相当于流的指针在尾端

​ 3) write(int):写入单个字符

​ 4) write(char[]):写入指定数组

​ 5) write(char[],off,len):写入指定数组的指定部分

​ 6) write (string) :写入整个字符串

​ 7) write(string,off,len):写入字符串的指定部分

​ 相关API:

​ String类: toCharArray:将String转换成char[]

​ 注意:

​ FileWriter使用后,必须要关闭(close)或刷新(flush),否则写入不到指定的文件!

节点流和处理流

节点流和处理流的区别和联系

​ 1.节点流是底层流/低级流,直接跟数据源相接。

​ 2.处理流包装节点流,既可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输入输出。[源码理解]。

​ 3.处理流(也叫包装流)对节点流进行包装,使用了修饰器设计模式,不会直接与数据源相连[模拟修饰器设计模式]。

处理流的功能主要体现在以下两个方面:

​ 1.性能的提高:主要以增加缓冲的方式来提高输入输出的效率。

​ 2.操作的便捷:处理流可能提供了一系列便捷的方法来次输入输出大批量的数据, 使用更加灵活方便。

对象流-ObjectlnputStream和ObjectOutputStream

​ 1.将int num = 100这个int数据保存到文件中,注意不是100数字,而是int 100,并且,能够从文件中直接恢复int 100

​ 2.将Dog dog = new Dog(”小黄”, 3)这个dog对象保存到文件中,并且能够从文件恢复.

​ 3.上面的要求, 就是能够将基本数据类型或者对象进行序列化和反序列化操作

序列化和反序列化

  1. 序列化就是在保存数据时,保存数据的值和数据类型

  2. 列化就是在恢复数据时,恢复数据的值和数据类型

  3. 需要让某个对象支持序列化机制,则必须让其类是可序列化的,为了让某个类是可序列化的,该类必须实现如下两个接口之一:

    Serializable / 这是一个标记接口

    Externalizable

注意事项和细节说明

​ 1)读写顺序要一致

​ 2)要求实现序列化或反序列化对象,需要实现Serializable

​ 3)序列化的类中建议添加SerialVersionUID,为了提高版本的兼容性

​ 4)序列化对象时,默认将里面所有属性都进行序列化,但除了static或transient修饰的成员

​ 5)序列化对象时,要求里面属性的类型也需要实现序列化接口

​ 6)序列化具备可继承性,也就是如果某类已经实现了序列化,则它的所有子类也已经默认实现了序列化

标准输入输出流

System.in标准输入InputStream键盘
System.out标准输出OutPutStream显示器

转换流

InputStreamReader
OutputStreamWriter

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值