Java-day09-IO和序列化

一:IO流

  •  io流(input/output)

  •  作用:实现两个设备之间数据的通信
  •   设备:磁盘(硬盘),内存,键盘,文件,网络,控制台

         网络:当前主机之外的网上资源

  • 分类:    

            根据操作的方式:输入流和输出流;

            根据数据的类型:字节流和字符流

  • 字节流:传输的是字节,可以操作任意类型的文件  ----音频,视频,文件,图片等     
  • 字符流:传输的是字节,不同点是在传输过程中加入了编码的操作,让我们的操作更方便  -----文本

 

  • 以内存为参考 :

           字节流:

                        字节输入流:InputStream

                        字节输出流:OutputStream      

           字符流的两个父类:

                         字符读入流(将数据输入内存):Reader

                         字符写出流(将数据从内存取出):Writer

  • 字符流与字节流的基本介绍

        字符流:----传输的是字符,只能传输字符
                         字符写出流   Writer
                              write()  write(字符数组) write(字符串)
                         字符读入流   Reader
                              read()  read(数组)
                         字符缓冲写出流   BufferedWriter
                              newline()  跨平台换行
                         字符缓冲读入流   BufferedReader
                              readLine() 读一行
        字节流:---传输的是字节,可以传输任何类型的数据
                         字节输出流     OutputStream
                         字节输入流     InputStream
                         字节缓冲输出流     BufferedOutputStream
                         字节缓冲输入流     BufferedInputStream

  •  字符流

  •  以磁盘的数据存储为例,将数据写入文件   

        分析:因为操作的是文本,所以使用字符流

                   写入文件-----写出流------FileWriter

  • 写内容---FileWriter
  •   代码
package com.qf.test;

import java.io.FileWriter;
import java.io.IOException;

public class Demo1 {
	public static void main(String[] args) throws IOException {
		//1创建FileWriter对象并关联相应的文件
		//注意点:
		//一:如果只写文件的名字,不写具体路径,默认路径是当前的工程
		//二:对于关联的文件,如果之前不存在,程序会自动创建一个,如果存在,会将原来的内容覆盖
		//三:可以自己指定路径,但是必须保证路径是真实存在的,否则报异常---FileNotFountException(系统找不到指定的路径。)
		FileWriter fileWriter = new FileWriter("test1.txt");
		
		//2.写
		//注意点四:在执行write方法时,数据被临时放到了流对象的内部数组中,这个数组是一个字节数组,会默认去查编码表
		fileWriter.write("chenchen");
		
		//3.//刷新---将临时数组中的数据放入磁盘
		//fileWriter.flush();
		//4.关闭流--两个功能:a:关闭流  b:刷新
		//第五个注意点:流对象使用完后必须关闭
		fileWriter.close();
		//第六个注意点:当流对象关闭之后,不能再进行操作,否则会报异常:Stream closed
		//fileWriter.write("haha");
	}
}
  •   文件的续写:FileWriter(String file,boolean value)

          当value为true的时候,不会将原来的内容覆盖,会接着写

  • 代码

    

package com.qf.test;

import java.io.FileWriter;
import java.io.IOException;

public class Demo2 {
	public static void main(String[] args) {
		//1.
		FileWriter fileWriter = null;
		try {
			fileWriter = new FileWriter("test2.txt",true);
			
			fileWriter.write("haha");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if (fileWriter != null) {
				try {
					fileWriter.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
}
  • 读内容----FileReader

       实例:从文件中读取内容,并显示在控制台-------FileReader

        int  read() ----一个字符一个字符的读,每次读出一个字符(返回的是ASCII码 0--65535,读到末尾为-1)

  •   代码
package com.qf.test;
import java.io.FileReader;
import java.io.IOException;

public class Demo3 {
	public static void main(String[] args) throws IOException {
		//1.创建FileReader的对象
		FileReader fileReader = new FileReader("test2.txt");
		//2.读
		/*
		 * read():一个字符一个字符的读,每次读出一个字符
		 * read(数组):一次可以读出多个字符   ,数组的作用:每次会将读出的字符临时放到这个数组中
		 */
		//read():一个字符一个字符的读,每次读出一个字符
		int  num = 0;
//		num = fileReader.read();//返回的是ASCII码
//		System.out.println((char)num);
//		num = fileReader.read();
//		System.out.println((char)num);
//		num = fileReader.read();
//		System.out.println((char)num);
//		num = fileReader.read();
//		System.out.println((char)num);
//		num = fileReader.read();
//		System.out.println((char)num);
//		num = fileReader.read();
//		System.out.println(num);
		while ((num = fileReader.read())!= -1) {
			System.out.println((char)num);
		}
		//3.关闭资源
		fileReader.close();
	}
}

     read(数组):一次可以读出多个字符,数组的作用:每次会将读出的字符临时放到这个数组中

                          数组的大小决定我们一次可以读到的字符个数,一般数组大小<=1kb  返回值代表本次读到的真实的字符个数,如果返回值是-1代表读完了

  • 代码
package com.qf.test;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;

public class Demo4 {
	public static void main(String[] args) throws IOException {
		//1.
		FileReader fileReader = new FileReader("test2.txt");
		//2.
		/*
		 * read():一个字符一个字符的读,每次读出一个字符
		 * read(数组):一次可以读出多个字符   ,数组的作用:每次会将读出的字符临时放到这个数组中
		 */
		//read(数组):一次可以读出多个字符   ,数组的作用:每次会将读出的字符临时放到这个数组中
		/* 数组是临时存放数据的地方,我们会将读到的字符放到临时数组中,数组的大小决定了我们一次可以读到的字符个数.
		 * 一般这个数组的大小<=1kB
		 * 返回值代表本次读到的真实的字符个数,如果返回值是-1代表读完了.
		 */
		char[] arr = new char[2];
		int num = 0;
//		num = fileReader.read(arr);
//		System.out.println(Arrays.toString(arr)+"     num:"+num);
//		num = fileReader.read(arr);
//		System.out.println(Arrays.toString(arr)+"     num:"+num);
//		num = fileReader.read(arr);
//		System.out.println(new String(arr,0,num)+"     num:"+num);
//		num = fileReader.read(arr);
//		System.out.println(Arrays.toString(arr)+"     num:"+num);
		
		while ((num = fileReader.read(arr)) != -1) {
			System.out.println(new String(arr,0,num)+"     num:"+num);
		}
		fileReader.close();
	}
}
  •   实例:完成文件的复制

              (\代表转义字符    \t:制表符    \n换行符     \\:表示普通的\   在代表路径的时候,\\与 / 是一个意思 )

  •  代码 

   

package com.qf.test;

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

/*
 * 实例:完成文件的复制
 * 将Demo1的东西复制到Demo1copy.java
 * 
 * D:\workspace\BigDataSZ1903N19\src\com\qianfeng\test\Demo1.java:绝对路径
 * BigDataSZ1903N19\src\com\qianfeng\test\Demo1.java:相对路径
 * 
 * 相对路径:从路径中间的某个部位开始一直到当前的文件
 * 绝对路径:一个文件的完整路径,从根目录开始到当前的文件
 */

public class Demo5 {
	public static void main(String[] args) throws IOException {
		//1.创建读入流和写出流
		FileReader fileReader = new FileReader("D:\\workspace/BigData1923N19\\src\\com\\qf\\test\\Demo1.java");
		FileWriter fileWriter = new FileWriter("Demo1copy.java");
		
		//读写
		//使用一次读一个
		int num =0 ;
//		while ((num = fileReader.read()) != -1) {
//			fileWriter.write(num);//可以实现自动转换
//			fileWriter.flush();
//		}
		
		//使用一次读多行
		char[] arr = new char[10];
		while ((num = fileReader.read(arr)) != -1) {
			fileWriter.write(arr,0,num);//可以实现自动转换
			fileWriter.flush();
		}
		
		fileReader.close();
		fileWriter.close();
	}
}
  •   字符缓冲流(字符缓冲区)

         定义:为了提高读写的能力,本身没有读写的能力想要进行读写就必须借助于字符流实现

         可以将缓冲流类比于催化剂

         字符缓冲流分类:

         字符缓冲读入流:BufferReader    没有读的能力

         字符缓冲写出流:BufferWriter      没有写的能力

    注意:window系统  换行符  \r\n    linux/unix   换行符    \n

           bufferedWriter.write("\r\n")   //换行

           bufferedWriter.newLine()  //换行---支持跨平台

  • 代码
package com.qf.test;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class Demo6 {
	public static void main(String[] args) throws IOException {
		//0.创建字符写出流对象
		//1.创建字符缓冲写出流对象
		BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("text3.txt"));
		//2.写
		bufferedWriter.write("bingbing");
		//windows系统   换行符   \r\n    linux/unix  换行符   \n
		//bufferedWriter.write("\r\n");//换行
		bufferedWriter.newLine();//换行---支持跨平台
		bufferedWriter.write("chenchen");
		//3.关闭资源 a.关闭内部的写出流     b.关闭自己   c.刷新
		bufferedWriter.close();
	}
}

          字符缓冲读入流  ------    一次读一个字符  int read()

                                                一次读多个字符   int read(char[] arr)

                                                一次读一行  String   readLine() 

                                                原理:一个字符一个字符的读,直到读到换行符为止,然后将所有读到的字符返回

                                                注意点:不会讲当前的换行符返回;返回值就是我们读到的内容,如果读完了,返回null

  •  代码
package com.qf.test;

import java.io.FileReader;
import java.io.IOException;
import java.io.BufferedReader;

public class Demo7 {
	public static void main(String[] args) throws IOException {
		//1.创建字符缓冲读入流
		BufferedReader bufferedReader = new BufferedReader(new FileReader("text3.txt"));
		//读
		//一次读一个字符
		int num = 0;
//		while ((num = bufferedReader.read()) != -1) {
//			System.out.print((char)num);
//		}
		
		//一次读多个字符
//		char[] arr = new char[5];
//   	while ((num = bufferedReader.read(arr)) != -1) {
//			System.out.print(new String(arr,0,num));
//		}
		
		//一次读一行  readline()
		//原理:一个字符一个字符的读,直到读到换行符为止.然后将所有读到的字符返回
		//注意点:不会将当前的换行符返回 ;返回值就是我们读到的内容.如果读完了,返回null
		String data = null;
		while ((data = bufferedReader.readLine()) != null) {
			System.out.print(data);
			//System.out.println();//换行
			System.out.print("\r\n");
		}
		bufferedReader.close();
	}
}
  •  实例:使用缓冲流实现文件的复制
package com.qf.test;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

/*
 * 使用缓冲流实现文件的复制
 */
public class Demo8 {
	public static void main(String[] args) throws IOException {
		//1.创建读入流和写出流
		FileReader fileReader = new FileReader("D:\\workspace/BigData1923N19\\src\\com\\qf\\test\\Demo1.java");
		FileWriter fileWriter = new FileWriter("Demo1copy.java");
		BufferedReader bufferedReader = new BufferedReader(fileReader);
		BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
		//读写
		//使用一次读一个
		int num =0 ;
		while ((num = bufferedReader.read()) != -1) {
			bufferedWriter.write(num);//可以实现自动转换
			fileWriter.flush();
		}
		
		//使用一次读多行
//		char[] arr = new char[10];
//		while ((num = bufferedReader.read(arr)) != -1) {
//			bufferedWriter.write(arr,0,num);//可以实现自动转换
//			fileWriter.flush();
//		}
		
		//使用一次读一行
		String data = null;
		while ((data = bufferedReader.readLine()) != null) {
			bufferedWriter.write(data);
			bufferedWriter.newLine();
			bufferedWriter.flush();
		}
		
		bufferedReader.close();
		bufferedWriter.close();

	}
}
  • 模拟字符缓冲读入流BufferedReader

       分析:

          1.要属于流的体系

          2.要有一个Reader类型的成员变量

          3.要有一个带参数的构造方法接收外部传入的流对象

          4.模拟readLine(),实现读一行的功能

          5.关闭流

  •  代码

   

import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
//1.要属于流的体系
class MyBufferedReader extends Reader{
	//2.要有一个Reader类型的成员变量
	Reader reader;
	//3.要有一个带参数的构造方法接收外部传入的流对象
	public MyBufferedReader(Reader reader) {
		this.reader = reader;
	}
	//4.模拟readLine(),实现读一行的功能
	public String readLine() throws IOException {
		//a.创建一个临时的可变字符串,用于装当前行的字符
		StringBuffer stringBuffer = new StringBuffer();
		//b.使用read()方法读
		int num = 0;
		while ((num = this.reader.read()) != -1) {
			if (num == '\r') {
				continue;
			}else if (num == '\n') {
				return stringBuffer.toString();
			}else {
				stringBuffer.append((char)num);
			}
		}
		
		//当文本为空时
		if (stringBuffer.length() == 0) {
			return null;
		}
		
		//当文本只有一行,没有换行符
		return stringBuffer.toString();
		
		//增加效率的代码
	}
	//5.关闭流
	public void close() throws IOException {
		//关闭自己
		this.reader.close();	
	}
	@Override
	public int read(char[] cbuf, int off, int len) throws IOException {
		// TODO Auto-generated method stub
		return 0;
	}
	
	
}
public class Demo1 {
	public static void main(String[] args) throws IOException {
		MyBufferedReader myBufferedReader = new MyBufferedReader(new FileReader("text3.txt"));
		String data = null;
		while ((data = myBufferedReader.readLine()) != null) {
			System.out.print(data);
			System.out.println();
		}
		myBufferedReader.close();
	}
}
  •  LineNumberReader : 时BufferedReader的子类,不能读,但是可以提高效率,特有功能:设置行号,获取行号

  • 代码
package com.qf.test;

import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;

public class Demo2 {
	public static void main(String[] args) throws IOException {
		LineNumberReader lineNumberReader = new LineNumberReader(new FileReader("D:\\workspace/BigData1923N19\\src\\com\\qf\\test\\Demo1.java"));
		//设置行号,默认从0开始,从1开始打印
		lineNumberReader.setLineNumber(10);
		String data = null;
		while ((data = lineNumberReader.readLine()) != null) {
			System.out.print(lineNumberReader.getLineNumber());//获取行号
			System.out.print(data);
			System.out.println();
		}
		lineNumberReader.close();
	}
}
  •  字节流

  •  FileInputStream与FileOutputStream

        FileInputStream  read()   read(byte[] b)

        FileOutputStream write(byte[]  b)

  •  代码
package com.qf.test;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class Demo3 {
	public static void main(String[] args) throws IOException {
		//写入数据
		write();
		//读1
		read1();
		//读2
		read2();
		//读3
		read3();
	}
	//将数据写入磁盘
	public static void write() throws IOException {
		//1.创建字节输出流并关联文件
		FileOutputStream fileOutputStream = new FileOutputStream("test1.txt");
		//2.写--这里只能写字节
		fileOutputStream.write("bingbing".getBytes());
		//3.关闭资源
		fileOutputStream.close();
	}
	//读1 一次读一个字节
	public static void read1() throws IOException {
		//1.创建字节输入流并关联文件
		FileInputStream fileInputStream = new FileInputStream("test1.txt");
		//2.读
		int num = 0;
		while ((num = fileInputStream.read()) != -1) {
			System.out.print((char)num);
		}
		//3.关闭资源
		fileInputStream.close();
	}
	//读2   一次读多个字节
	public static void read2() throws IOException {
		//1.创建字节输入流并关联文件
		FileInputStream fileInputStream = new FileInputStream("test1.txt");
		//2.读
		int num = 0;
		byte[] bytes = new byte[5];
		while ((num = fileInputStream.read(bytes)) != -1) {
			System.out.print(new String(bytes,0,num));
		}
		//3.关闭资源
		fileInputStream.close();
	}
	//读3  一次全部读完
	public static void read3() throws IOException {
		//1.创建字节输入流并关联文件
		FileInputStream fileInputStream = new FileInputStream("test1.txt");
		//获取文件的字节个数
		//注意:这种方式适合文件的字节数比较小的时候,大概是几kb之内.
		int num1 = fileInputStream.available();
		//2.读
		byte[] bytes = new byte[num1];
		fileInputStream.read(bytes);
		System.out.println(new String(bytes));
		//3.关闭资源
		fileInputStream.close();
	}
}

 

  • 字节缓冲流 BufferedInputStream  BufferedOutputStream

  •  代码(利用字节缓冲流实现图片的复制)
package com.qf.test;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Demo5 {
	public static void main(String[] args) throws IOException {
		/*
		 * 使用字节缓冲流实现图片的复制
		 */
		//1.创建字节输入流
		FileInputStream fileInputStream = new FileInputStream("D:\\workspace\\BigData1923N20\\100.jpg");
		BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
		//2.创建字节输出流
		FileOutputStream fileOutputStream  = new FileOutputStream("D:\\workspace\\BigData1923N20\\100copy1.jpg");
		BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
		//3.进行读写
		int num = 0;
		while ((num = bufferedInputStream.read()) != -1) {
			bufferedOutputStream.write(num);
		}

		bufferedInputStream.close();
		bufferedOutputStream.close();
	}
}
  •  标准输入输出流

         标准输入流:--- System.in:"标准"输入流。此流已打开并准备提供输入数据。通常,此流对应于键盘输入或者由主机环境或用户指定的另一个输入源。

                              输入源:可以发送数据的设备       输出源:可以接受数据的设备

                              1.当前的流已经打开并关联了输入源---键盘

                              2.如果不想让键盘充当输入源,可以通过steIn进行更换  

                              3.是一个字节流

         标准输出流:---System.out

  •  代码
package com.qf.test;

import java.io.IOException;
import java.io.InputStream;


public class Demo6 {
	public static void main(String[] args) throws IOException {
		InputStream inputStream = System.in;
		//int num = inputStream.read();//把标准输入流的read方法称为阻塞式方法
		/*
		 * 实例:实现从键盘不断接收字符的程序
		 * 要求:一行一行的接收
		 */
		myReadLine(inputStream);
	}
	
	public static void myReadLine(InputStream inputStream) throws IOException {
		StringBuffer stringBuffer = new StringBuffer();
		while (true) {
			int num = inputStream.read();
			if (num == '\r') {
				continue;
			}else if (num == '\n') {
				System.out.println(stringBuffer.toString());
				//当用户输入over的时候,结束程序
				if (stringBuffer.toString().equals("over")) {
					break;
				}
				
				//将上一次的值清除掉
				stringBuffer.delete(0, stringBuffer.length());
			}else {
				stringBuffer.append((char)num);
			}
		}
	}
}

 

  •  不同输入输出源代码的演示
package com.qf.test;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class Demo8 {
	public static void main(String[] args) throws IOException {
		/*
		 * 设备之间数据传输的总结:
		 * 输入源:键盘
		 * 输出源:控制台
		 * 
		 * 输入源:键盘
		 * 输出源:文件
		 * 
		 * 输入源:文件
		 * 输出源:控制台
		 * 
		 * 输入源:文件
		 * 输出源:文件
		 */
    	//将键盘作为输入源
    	BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
    	//将文件作为输入源
    	BufferedReader bufferedReader1 = new BufferedReader(new FileReader("temp1.txt"));
    	//将控制台作为输出源
		BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(System.out));
		//将文件作为输出源
		BufferedWriter bufferedWriter1 = new BufferedWriter(new FileWriter("temp2.txt"));
		
//		 * 输入源:键盘
//		 * 输出源:控制台
		 String data = null;
		 while ((data = bufferedReader.readLine()) != null) {
			bufferedWriter.write(data);
			bufferedWriter.newLine();
			
			bufferedWriter.flush();
		}
//		 * 输入源:键盘
//		 * 输出源:文件

//		 * 输入源:文件
//		 * 输出源:控制台

//		 * 输入源:文件
//		 * 输出源:文件
		
		bufferedReader.close();
		bufferedReader1.close();
		bufferedWriter.close();
		bufferedWriter1.close();
	}
}

  •  更换输出元  System.setIn()方法代码的演示

         注意:这里是临时更换,只能在当前程序中使用更换后的输入源输出源,如果在其他的程序中会自动变回原来的输入源输出源

package com.qf.test;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintStream;

public class Demo9 {
	public static void main(String[] args) throws IOException {
		//更换输入源
		//注意:这里是临时更换,只能在当前程序中使用更换后的输入源输出源,如果在其他的程序中会自动变回原来的输入源输出源
		//从键盘接收数据更替成从文件接收数据
		System.setIn(new FileInputStream("D:\\workspace\\BigData1923N20\\src\\com\\qf\\test\\Demo1.java"));
		//从输出到控制台更替成输出到文件
		System.setOut(new PrintStream("D:\\workspace\\BigData1924N11\\Democopy.java"));
		
		BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(System.out));
		
		String data = null;
		while ((data = bufferedReader.readLine()) != null) {
			bufferedWriter.write(data);
			bufferedWriter.newLine();
			bufferedWriter.flush();
		}
		
		bufferedReader.close();
		bufferedWriter.close();
	}
}

 

  •  转换流

        InputStreamReader:输出转换流

        OutputStreamWriter:输入转换流

        实现的是从字节流到字符流,本身是字符流

        模拟的场景:使用字符缓冲流的readline和newline方法实现字节流的功能 

  •  代码
package com.qf.test;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;


public class Demo7 {
	public static void main(String[] args) throws IOException {
		//1将标准字节输入流转成字符缓冲读入流
		BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
		//2.将标准字节输出流转成字符缓冲写出流
		BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(System.out));
		//3.读写
		String data = null;
		while ((data = bufferedReader.readLine()) != null) {
			bufferedWriter.write(data);
			bufferedWriter.newLine();
			bufferedWriter.flush();
			//当输入的内容是over时,结束
			if (data.equals("over")) {
				break;
			}
		}
		bufferedReader.close();
		bufferedWriter.close();
	}
}
  •  打印流

         字节打印流:PrintStream:除了拥有输出流的特点之外,还有打印的功能

         字符打印流:PrintWriter

         字节打印流支持的设备:

         1.File类型的文件

         2.字符串类型的文件

         3.字节输出流

  • 字节打印流代码
package com.qf.test;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;


public class Demo10 {
	public static void main(String[] args) throws IOException {
		PrintStream printStream1 = new PrintStream(new File("test2.txt"));
		PrintStream printStream2 = new PrintStream("test2.txt");
		PrintStream printStream3 = new PrintStream(new FileOutputStream("test.txt"));
		printStream3.println("haha");
		printStream1.close();
		printStream2.close();
		printStream3.close();
		
		PrintStream printStream4 = new PrintStream(new FileOutputStream("test5.txt"));
		printStream4.write(97);//00000000 00000000 00000000 01100001  默认将前三个字节砍掉     01100001  a
		printStream4.write(353);//00000000 00000000 00000001 01100001  默认将前三个字节砍掉  01100001  a
		printStream4.print(353);
		//这是print方法的内部实现原理
		//先将353转成字符串再转成字节数组
		printStream4.write(String.valueOf(353).getBytes());
		printStream4.close();
	}
}

         字符打印流支持的设备:

                1.File类型的文件

                2.字符串类型的文件

                3.字节输出流

                4.字符输出流

                eg :  public  PrintWriter(Writer out, boolean autoFlush)

                        autoFlush - boolean 变量 :如果为true, 则println、printf、format方法将刷新输出缓冲区

  •  代码
package com.qf.test;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;


public class Demo11 {
	public static void main(String[] args) throws IOException {
		//3.支持字节输出流
		PrintWriter printWriter = new PrintWriter(new FileOutputStream("test6.txt"));
		//4.支持字符写出流
		PrintWriter printWriter2 = new PrintWriter(new FileWriter("test6.txt"));
		printWriter.close();
		printWriter2.close();
	}
}
  • Properties

      实际上就是Map集合,存储的是属性,属性以键值对的方式存储,这里的键和值都必须是字符串,所以不需要考虑泛型

       Properties的使用和流紧密相关

       优点:1.以键值对的形似存储数据

                  2.内部针对属性的存储封装了大量专有方法:load、store、list

     1 . Properties的基础

//1.Properties的基础
	public static void fun1() {
		//创建对象
		Properties properties = new Properties();
		properties.setProperty("a", "java");
		properties.setProperty("b", "html");
		System.out.println(properties);  //  {b=html, a=java}
		//根据key取值
		System.out.println(properties.getProperty("a"));  // java
		//key是唯一的
		Object object = properties.setProperty("a", "BigData");  
		System.out.println(object);    //java
		//当前的key在Properties中不存在时,会打印python
		System.out.println(properties.getProperty("c", "python"));
		
	}

       2.利用Properties获取系统属性

public static void fun2() {
		Properties properties = System.getProperties();
		//遍历
		Set<String> set = properties.stringPropertyNames();
//		Iterator<String> iterator = set.iterator();
//		while (iterator.hasNext()) {
//			String string = (String) iterator.next();
//			System.out.println("key:"+string+"    value:"+properties.getProperty(string));
//		}
		//增强for循环
		for (String key : set) {
			System.out.println("key:"+key+"    value:"+properties.getProperty(key));
		}
		//对系统属性的某个属性进行更改
		properties.setProperty("sun.jnu.encoding", "UTF8");
		System.out.println(properties.getProperty("sun.jnu.encoding"));
		
		//重新获取一遍值
		//原理:会先到内存中找属性集合的对象,如果有,直接使用.如果没有,会重新初始化一个新的对象,并获取属性集合.
		Properties properties1 = System.getProperties();
		System.out.println(properties1.getProperty("sun.jnu.encoding"));
		
		properties1.list(System.out);
	}

     3.Peoperties在实际中的应用

public static void fun3() throws FileNotFoundException, IOException {
		//创建Properties对象
		Properties properties = new Properties();
		//利用load方法将内容从磁盘读到内存
		//注意:使用的文件内容的格式应用是key=value
		properties.load(new FileReader("text3.txt"));
		
		properties.list(System.out);
		
		//更改内容
		properties.setProperty("a", "hehe");
		//写会磁盘  第二个参数是提醒信息
		properties.store(new FileWriter("text3.txt"), "hello world");
	}
  •  序列化

    将短期存储的数据实现长期存储,这个过程对应的流就是序列化流

  •   数据的存储分成两类:

         1.短期存储:存放在内存中,随着程序的关闭而释放----对象,集合,变量,数组

         2.长期存储:存储在磁盘中,即使程序关闭了,数据仍然存在---文件

  • 序列化:将数据从内存放入磁盘,可以实现数据的长久保存---数据持久化的手段
  • 反序列化:将数据从磁盘放回内存
  • 进行序列化的步骤----通过对象的序列化讲解

        1.创建一个类

        2.使用对应的流将对象存入磁盘中----序列化-----ObjectOutputStream

        3.使用对应的流将对象从磁盘中取出放回内存----反序列化----ObjectInputStream

        4.关闭流

        注意点:序列化流在工作时也要关联对应的基本输入输出流

      解释:
             一个类如果没有实现Serializable,进行序列化会报异常:NotSerializableException
    

  •    实现了Serializable接口的类可以达到的目的:

           1.可以进行序列化
           2.进行序列化的类的元素都必须支持序列化
           3.接口本身没有方法或字段,只是用来表示可序列化的语义

  •  注意点

           1. ClassNotFoundException:当前的类没有找到
               分析:将Person对象进行序列化之后,将Person类删除,再进行反序列化的时候出现了异常
               原因:反序列化在执行的时候依赖字节码文件,当类没有了,字节码文件无法创建,反序列化失败
  
           2.java.io.InvalidClassException  无效的类
               出现的原因:没有声明自己的serialVersionUID,而使用系统的.在进行反序列化的时候,类被改动了,系统认为现在的类
               已经不是原来的类了(在使用系统的id进行识别的时候,重写给Person设置了id),认为此类无效
  
           3.使用系统的serialVersionUID与自定义的ID的区别?
               使用系统的,序列化和反序列化,id不能手动设置,使用的是编译器默认生成的,一旦类发生了改动,id会重新赋值
               使用自定义的,序列化和反序列化,id不会发生改变,所以当反序列化的时候,即使对Person类进行了一些改动,也能继续反序列化 

           4.总结序列化,反序列化工程的注意点:
               a.合理使用序列化流和反序列化流,要与输入流与输出流配合使用
               b.进行序列化的类一定要实现Serializable接口,只要实现了接口就可以序列化.包括集合,包装类等
               c.进行序列化的类要保证当前类与内部的类都要实现Serializable接口

           5.当一个属性被transient修饰后,这个对象在序列化时属性的值会被忽略,忽略不必要的属性可以达到对象序列化“瘦身”的功能

  •  序列化与反序列化代码的演示
package com.qf.test;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

//要想让Person类的对象可以实现序列化,必须让Person类实现Serializable接口
//类通过实现 java.io.Serializable 接口以启用其序列化功能。
//未实现此接口的类将无法使其任何状态序列化或反序列化。
//可序列化类的所有子类型本身都是可序列化的。序列化接口没有方法或字段,
//仅用于标识可序列化的语义
//注意:不仅要求当前类可序列化,而且要求当前类的所有子类型本身都是可序列化的(比如:ArrayList)
class Person implements Serializable{
//	 /**
//		 * generated:由编译器自动生成的,后面加L表示long型
//		 */
		private static final long serialVersionUID = -7224641225172644265L;
//		/**
//		 * default:UID是由用户自己指定的,默认值是1L
//		 */
//		private static final long serialVersionUID = 1L;
	String name;
	//int age;
	public Person(String name) {
		this.name = name;
	}
	public String toString() {
		return "Person [name=" + name + "]";
	}
}
public class Demo13 {
	public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
		//对象的序列化
		//objectWrite();
		//对象的逆序列化流
		objectRead();
	}
	//对象的序列化
//	public static void objectWrite() throws FileNotFoundException, IOException {
//		
//		ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("test6.txt"));
//		//objectOutputStream.writeInt(100);
//		//对象序列化
//		Person person = new Person("bingbing");
//		objectOutputStream.writeObject(person);
//		objectOutputStream.close();
//	}
	
	//对象的逆序列化流
	//序列化的东西要通过逆序列化流读取
	public static void objectRead() throws FileNotFoundException, IOException, ClassNotFoundException {
		ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("test6.txt"));
//		int value = objectInputStream.readInt();
//		System.out.println(value);
		Object object = objectInputStream.readObject();
		System.out.println(object);
		objectInputStream.close();
	}
}
  •  文件File类

    File类,用来操作文件和路径(目录)

  •  api代码的演示
package com.qf.test;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Demo14 {
	public static void main(String[] args) throws IOException {
		/*
		 * 文件:File类,用来操作文件和路径(目录)
		 * 
		 * 创建文件
		 * 创建路径
		 * 创建多路径
		 * 
		 * 判断是否是文件
		 * 判断是否是路径
		 * 判断是否隐藏
		 * 获取最后修改文件的时间
		 * 
		 * 获取根目录(路径)
		 * 获取指定目录下的文件或文件夹
		 */
		//创建File类的对象
		//第一种方式:直接指定文件的绝对路径
		File file1 = new File("D:\\workspace\\BigData1923N21\\src\\com\\qf\\test\\Demo1.java");
		//第二种:通过父路径和子路径的字符串形式
		File file2 = new File("D:\\workspace\\BigData1923N21","src\\com\\qf\\test\\Demo1.java");
		//第三种:先得到父路径的对象形式,再跟子路径拼接
		File file3 = new File("D:\\workspace\\BigData1923N21");
		File file4 = new File(file3,"src\\com\\qf\\test\\Demo1.java");
//		 * 创建文件,在创建时,如果当前的文件已经存在了,不会覆盖
		File file5 = new File("D:\\workspace\\BigData1923N21\\test1.txt");
		file5.createNewFile();
//		 * 创建单层路径,只能创建单层路径,只能创建目录
		File file6 = new File("D:\\workspace\\BigData1924N11\\a\\test2.txt");
		//file6.mkdir();
//		 * 创建多路径,也可创建单层目录,只能创建目录
		file6.mkdirs();
		
//		 * 判断是否是文件
		System.out.println(file6.isFile());//false
//		 * 判断是否是路径
		System.out.println(file6.isDirectory());//true
//		 * 判断是否隐藏
		System.out.println(file6.isHidden());//false
//		 * 获取最后修改文件的时间
		long lastTime = file5.lastModified();
		System.out.println(lastTime);
		
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String value = simpleDateFormat.format(new Date(lastTime));
		System.out.println(value);
        
         * 获取根目录(路径)-当前主机的所有的根目录
		File[] files = File.listRoots();
		for (File file : files) {
			System.out.println(file);
		}
		System.out.println("***********************");
//		 * 获取指定目录下的文件或文件夹  特点:1.只获取的是当层的内容,不管子路径   2.只获取内容的名字,不是全路径
		File file = new File("D:\\\\workspace\\\\BigData1924N11");
		String[] strings = file.list();
		for (String string : strings) {
			System.out.println(string);
		}
		System.out.println("***********************");
		//获取指定目录下的文件或文件夹 的全路径
	    File[] file2 = file.listFiles();
	    for (File file3 : file2) {
			System.out.println(file3);
		}
	}
}
  •  递归

         有条件的自己调用自己(方法)

  •    条件:1.要给一个出口,负责结束当前的循环

                     2.循环的次数不能太多,否则占用内存量过大,死机

  • 代码

    

package com.qf.test;

public class Demo16 {
	public static void main(String[] args) {
		/*
     	 * 求:1-10之间的和
		 * 
          /
		Person10.run();
	}
}

class Person10{
	static int sum = 0;
	static int i=1;
	public static void run() {
		sum+=i;
		System.out.println(sum);
		if ( i++ == 10) {
			return;//给了一个出口
		}
		run();
	}
}

  •    序列流(了解):把多个输入流的内容一次性的打印(操作)---字节流

          代码演示:

          

package com.qf.test;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.SequenceInputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;

public class Demo18 {
	/*
	 * 序列流:把多个输入流的内容一次性的打印(操作)---字节流
	 */
	public static void main(String[] args) throws IOException {
		//创建三个输入流
		FileInputStream fileInputStream1 = new FileInputStream("src\\com\\qf\\test\\Demo2.java");
		FileInputStream fileInputStream2 = new FileInputStream("src\\com\\qf\\test\\Demo2.java");
		FileInputStream fileInputStream3 = new FileInputStream("src\\com\\qf\\test\\Demo1.java");
		
		//将三个输入流放入序列流
		//方式一:先放入一个Vector
//		Vector<FileInputStream> vector = new Vector<>();
//		vector.add(fileInputStream1);
//		vector.add(fileInputStream2);
//		vector.add(fileInputStream3);
//		
//		//得到枚举器
//		Enumeration<FileInputStream> e1 = vector.elements();
		
		//方式二:先放入一个list
		ArrayList<FileInputStream> list = new ArrayList<>();
		list.add(fileInputStream1);
		list.add(fileInputStream2);
		list.add(fileInputStream3);
		
		//将集合转换成枚举
		Enumeration<FileInputStream> e2 = Collections.enumeration(list);
		
		//创建序列流对象并关联相关的文件--参数是一个枚举器
		//SequenceInputStream sequenceInputStream = new SequenceInputStream(e1);
		SequenceInputStream sequenceInputStream = new SequenceInputStream(e2);
		
		//创建输出流
		FileOutputStream fileOutputStream = new FileOutputStream("temp2.txt");
		
		//读写
		byte[] arr = new byte[1024];
		int num;
		while ((num = sequenceInputStream.read(arr)) != -1) {
			fileOutputStream.write(arr, 0, num);
			
			fileOutputStream.flush();
		}
		
		sequenceInputStream.close();
		fileOutputStream.close();
		
		
	}
}
  • 数据流:字节流

        DataInputStream : 数据输入流

        DataOutputStream : 数据输出流

       注意:数据流要与字节输入流,输出流配合使用

     代码演示:

package com.qf.test;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Demo19 {
	
	public static void main(String[] args) throws IOException {
		
		//写
		writeData();
		
		//读
		readData();
	}
	
	public static void writeData() throws IOException {
		DataOutputStream dataOutputStream = new DataOutputStream(new FileOutputStream("temp3.txt"));
		
		//写
		dataOutputStream.writeInt(97);//4个字节      00000000 00000000 000000000 011000001  00000001
		dataOutputStream.writeBoolean(true);//1个   
		dataOutputStream.write(33);//1个
		dataOutputStream.writeDouble(34.56);//8个
		
		//关闭流
		dataOutputStream.close();
	}
	
	public static void readData() throws IOException {
		DataInputStream dataInputStream = new DataInputStream(new FileInputStream("temp3.txt"));
		
		//这里的boolean型和int型的数据,在读的时候由于与之前写的顺序相反了,所以读取的数据错误
		/*
		 * 注意点:1.读的顺序要与写的顺序一致   2.类型保持一致
		 */
		System.out.println(dataInputStream.readBoolean());// 00000000
		System.out.println(dataInputStream.readInt());//00000000 000000000 011000001  00000001
		
		System.out.println(dataInputStream.readByte());
		System.out.println(dataInputStream.readDouble());
		
		dataInputStream.close();
	}
	
	
}
  •   内存流(byte数组流)

         ByteArrayInputStream : 写入内存,在内部有一个数组,数据被放在这里面

         ByteArrayOutputStream : 将数据取出,放在字节数组里面

         代码演示:

package com.qf.test;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class Demo20 {
	public static void main(String[] args) throws IOException {
		
		//创建输入流,关联一个byte型的数组,作为缓冲区数据
		ByteArrayInputStream bais = new ByteArrayInputStream("hello world".getBytes());
		
		//创建输出流-不需要指定参数
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		
		byte[] arr = new byte[1024];
		int num;
		while ((num = bais.read(arr)) != -1) {
			baos.write(arr, 0, num);
		}
		
		System.out.println(new String(arr));
		
		bais.close();
		baos.close();
		
		//注意:将流关闭了之后,还可以调用方法,不会报错.
		baos.write(45);
	}
}
  •  字符集

  •   转换流的编码问题 : 

             中国的字符集:GBK/GB2312

             欧洲的 : ISO8859-1

             国际通用 : utf-8

             美国的 : ASCII

  •  编码:将字符串转换为byte序列的过程
  •  解码:将byte序列转换成字符串的过程

         编码错误:乱码:在执行读与写的时候,由于使用的字符集不同,造成了编码的错误

         解决方案:可以先编码再解码

  •  开发中的编码

        常用字符集:一个汉字:GBK : 2字节   ISO8859-1 : 1个字节    utf-8 : 3个字节    unicode : 2个字节(内部编码)

        utf-8,GBK是支持中文的,ISO8859-1不支持中文

  •  编码

         byte[ ] getBytes() //对于中文  默认的格式

         使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。 

         byte[] getBytes(Charset charset) 
         使用给定的 charset 将此 String 编码到 byte 序列,并将结果存储到新的 byte 数组。 

 

  •  解码

        new String(byte[] bytes) //对于中文  默认是格式
        通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String。

        new String(byte[] bytes, Charset charset) 
        通过使用指定的 charset 解码指定的 byte 数组,构造一个新的 String。

       代码演示:

public static void main(String[] args) throws UnsupportedEncodingException {
		//使用GBK编码,GBK解码
		String str1 = "你好";
		byte[] str1b = str1.getBytes("GBK");
		System.out.println(new String(str1b,"GBK"));//你好
		System.out.println(Arrays.toString(str1b));//[-60, -29, -70, -61]
		//使用utf-8编码,utf-8解码
		String str2 = "你好";
		byte[] str2b = str2.getBytes();
		System.out.println(new String(str2b));//你好
		System.out.println(Arrays.toString(str2b));//[-28, -67, -96, -27, -91, -67]
		//使用ISO8859-1编码,解码
		String str3 = "你好";
		byte[] str3b = str3.getBytes("ISO8859-1");
		System.out.println(new String(str3b,"ISO8859-1"));//??
		System.out.println(Arrays.toString(str3b));//[63, 63]
	}
  •  中文乱码出现的情况研究

         注意点:乱码解决的办法是再编码再解码
         但是如果是编码出错了,无法解决.如果是解码出错了,可以利用再编码再解码
         编码                     解码                  结果
         GBK                    utf8                   不可以(GBK2个字节,utf83个字节)
         GBK                    ISO8859-1        可以
         utf8                     GBK                  有时可以
         utf8                     ISO8859-1        可以
         ISO8859-1          GBK                  不可以(编码就出错了)   
         ISO8859-1          utf8                   不可以(编码就出错了)

         注意 : 因为中文在utf8中是三个字节,在gbk中是两个字节,所以单数个中文用utf8编码后再用gbk解码这时由于编码出的字节数是单数的,gbk解码会自动补充一个字节,不仅造成解码出现乱码,也导致在编码在解码也无法解决

        在编码在解码的演示

        String s1 = "你好";
		byte[] s1b = s1.getBytes("GBK");
		String sr1b = new String(s1b,"utf-8");
		System.out.println("utf8解码:"+sr1b);//???
		
		//再编码
		byte[] s1bb = sr1b.getBytes("utf-8");
		//再解码
		System.out.println("GBK再编码:"+new String(s1bb,"GBK"));//锟斤拷锟?
	

 

  •  装饰设计模式

  • 定义:基于已经实现的功能,提供增强的功能,装饰设计模式的由来就来自于对缓冲流的实现
  •  特点:从缓冲流的角度讲解

                  1.使流原来的继承体更加的简单

                  2.提高了效率

                  3.由于是在原来的基础上提高增强的功能,所以他还要属于原来的体系      

  •   演示:如果自己设计装饰设计模式,怎么处理?

          1.原来的类  Test---Reader

          2.装饰类  BTest----MyBufferedReader

          步骤:1.让BTest继承自Test

                     2.在BTest内有一个Test类型的成员变量。

                     3.通过BTest内一个带参数的构造方法接受外部传入的一个Test类型的对象,交给内部的Test的属性

                     4.在实现功能的时候,调用传入的Test类型的对象实现原有的功能,自己实现增强的功能

  • 适配器设计模式:通常可以变相地理解为装饰设计模式

       实例:要求在子类中只使用play方法

       分析:Dog是继承了ZiMidel类,ZiMidel类实现了Inter接口

       当Dog类想要实现Inter接口的一个方法的时候,如果直接实现Inter接口,就必须将所有的方法都实现

       如果在Dog类与Inter接口之间插入一个类,让这个类去实现Inter接口的所有方法,作为这个类的子类只需要实现自己需要的方法

        我们将中间的这个类就可以成为适配器类     

  •    代码
interface Inter{
	public void play();
	public void song();
	public void run();
	public void eat();
	public void jump();
}
//适配器类
class ZiMidel implements Inter{

	@Override
	public void play() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void song() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void eat() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void jump() {
		// TODO Auto-generated method stub
		
	}
	
}


//创建狗类,我只想让她实现play方法?
class Dog extends ZiMidel{
	public void play() {
		// TODO Auto-generated method stub
		
	}
}

class Cat extends ZiMidel{
	public void song() {
		
	}
}

             

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值